CUBRID Engine  latest
log_page_buffer.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_page_buffer.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 <stdarg.h>
31 #include <string.h>
32 #include <time.h>
33 #include <limits.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #if defined(WINDOWS)
37 #include <io.h>
38 #else /* !WINDOWS */
39 #include <unistd.h>
40 #endif /* !WINDOWS */
41 #include <stdarg.h>
42 
43 #if defined(SOLARIS)
44 #include <netdb.h>
45 #endif /* SOLARIS */
46 
47 #if !defined(WINDOWS)
48 #include <sys/param.h>
49 #include <fcntl.h>
50 #endif /* WINDOWS */
51 
52 #include <assert.h>
53 
54 #include "porting.h"
55 #include "porting_inline.hpp"
56 #include "connection_defs.h"
57 #include "language_support.h"
58 #include "log_append.hpp"
59 #include "log_impl.h"
60 #include "log_lsa.hpp"
61 #include "log_manager.h"
62 #include "log_comm.h"
63 #include "log_volids.hpp"
64 #include "log_writer.h"
65 #include "lock_manager.h"
66 #include "log_system_tran.hpp"
67 #include "boot_sr.h"
68 #if !defined(SERVER_MODE)
69 #include "boot_cl.h"
70 #else /* !SERVER_MODE */
71 #include "connection_defs.h"
72 #include "connection_sr.h"
73 #endif
74 #include "critical_section.h"
75 #include "page_buffer.h"
76 #include "double_write_buffer.h"
77 #include "file_io.h"
78 #include "disk_manager.h"
79 #include "error_manager.h"
80 #include "xserver_interface.h"
81 #include "perf_monitor.h"
82 #include "storage_common.h"
83 #include "system_parameter.h"
84 #include "memory_alloc.h"
85 #include "memory_hash.h"
86 #include "release_string.h"
87 #include "message_catalog.h"
88 #include "msgcat_set_log.hpp"
89 #include "environment_variable.h"
90 #include "util_func.h"
91 #include "errno.h"
92 #if defined(WINDOWS)
93 #include "wintcp.h"
94 #include "connection_error.h"
95 #else /* WINDOWS */
96 #include "tcp.h"
97 #endif /* WINDOWS */
98 #include "db.h" /* for db_Connect_status */
99 #include "log_compress.h"
100 #include "event_log.h"
101 #include "tsc_timer.h"
102 #include "vacuum.h"
103 #include "thread_entry.hpp"
104 #include "thread_manager.hpp"
105 #include "crypt_opfunc.h"
106 #include "object_representation.h"
107 
108 #if !defined(SERVER_MODE)
109 #define pthread_mutex_init(a, b)
110 #define pthread_mutex_destroy(a)
111 #define pthread_mutex_lock(a) 0
112 #define pthread_mutex_unlock(a)
113 static int rv;
114 #undef COND_INIT
115 #define COND_INIT(a)
116 #undef COND_BROADCAST
117 #define COND_BROADCAST(a)
118 #undef COND_DESTROY
119 #define COND_DESTROY(a)
120 #endif /* !SERVER_MODE */
121 
122 #define logpb_log(...) if (logpb_Logging) _er_log_debug (ARG_FILE_LINE, "LOGPB: " __VA_ARGS__)
123 #define log_archive_er_log(...) \
124  if (prm_get_bool_value (PRM_ID_DEBUG_LOG_ARCHIVES)) _er_log_debug (ARG_FILE_LINE, __VA_ARGS__)
125 
126 #define LOGPB_FIND_BUFPTR(bufid) &log_Pb.buffers[(bufid)]
127 
128 
129 /* PAGES OF ACTIVE LOG PORTION */
130 #define LOGPB_HEADER_PAGE_ID (-9) /* The first log page in the infinite log sequence. It is always kept
131  * on the active portion of the log. Log records are not stored on this
132  * page. This page is backed up in all archive logs */
133 #define LOGPB_NEXT_ARCHIVE_PAGE_ID (log_Gl.hdr.nxarv_pageid)
134 #define LOGPB_FIRST_ACTIVE_PAGE_ID (log_Gl.hdr.fpageid)
135 #define LOGPB_LAST_ACTIVE_PAGE_ID (log_Gl.hdr.nxarv_pageid + log_Gl.hdr.npages - 1)
136 #define LOGPB_ACTIVE_NPAGES (log_Gl.hdr.npages)
137 
138 /*
139  * TRANSLATING LOGICAL LOG PAGES (I.E., PAGES IN THE INFINITE LOG) TO PHYSICAL
140  * PAGES IN THE CURRENT LOG FILE
141  */
142 #define LOGPB_PHYSICAL_HEADER_PAGE_ID 0
143 
144 #define LOGPB_IS_FIRST_PHYSICAL_PAGE(pageid) (logpb_to_physical_pageid(pageid) == 1)
145 
146 /* ARCHIVE LOG PAGES */
147 #define LOGPB_IS_ARCHIVE_PAGE(pageid) \
148  ((pageid) != LOGPB_HEADER_PAGE_ID && (pageid) < LOGPB_NEXT_ARCHIVE_PAGE_ID)
149 #define LOGPB_AT_NEXT_ARCHIVE_PAGE_ID(pageid) \
150  (logpb_to_physical_pageid(pageid) == log_Gl.hdr.nxarv_phy_pageid)
151 
152 #define ARV_PAGE_INFO_TABLE_SIZE 256
153 
154 #define LOG_LAST_APPEND_PTR() ((char *) log_Gl.append.log_pgptr->area + LOGAREA_SIZE)
155 
156 #define LOG_APPEND_ALIGN(thread_p, current_setdirty) \
157  do { \
158  if ((current_setdirty) == LOG_SET_DIRTY) \
159  { \
160  logpb_set_dirty ((thread_p), log_Gl.append.log_pgptr); \
161  } \
162  log_Gl.hdr.append_lsa.offset = DB_ALIGN (log_Gl.hdr.append_lsa.offset, DOUBLE_ALIGNMENT); \
163  if (log_Gl.hdr.append_lsa.offset >= (int) LOGAREA_SIZE) \
164  { \
165  logpb_next_append_page((thread_p), LOG_DONT_SET_DIRTY); \
166  } \
167  } while (0)
168 
169 #define LOG_APPEND_ADVANCE_WHEN_DOESNOT_FIT(thread_p, length) \
170  do { \
171  if (log_Gl.hdr.append_lsa.offset + (int) (length) >= (int) LOGAREA_SIZE) \
172  { \
173  logpb_next_append_page ((thread_p), LOG_DONT_SET_DIRTY); \
174  } \
175  } while (0)
176 
177 #define LOG_APPEND_SETDIRTY_ADD_ALIGN(thread_p, add) \
178  do { \
179  log_Gl.hdr.append_lsa.offset += (add); \
180  LOG_APPEND_ALIGN ((thread_p), LOG_SET_DIRTY); \
181  } while (0)
182 
183 /* LOG BUFFER STRUCTURE */
184 
185 typedef struct log_buffer LOG_BUFFER;
187 {
188  volatile LOG_PAGEID pageid; /* Logical page of the log. (Page identifier of the infinite log) */
189  volatile LOG_PHY_PAGEID phy_pageid; /* Physical pageid for the active log portion */
190  bool dirty; /* Is page dirty */
191  LOG_PAGE *logpage; /* The actual buffered log page */
192 };
193 
194 /* Status for append record status during logpb_flush_all_append_pages.
195  * In normal conditions, only two statuses are used:
196  * - LOGPB_APPENDREC_IN_PROGRESS (set when append record is started)
197  * - LOGPB_APPENDREC_SUCCESS (set when append record is ended).
198  *
199  * If a log record append is not ended during flush, then we'll transition the states in the following order:
200  * - LOGPB_APPENDREC_IN_PROGRESS => LOGPB_APPENDREC_PARTIAL_FLUSHED_END_OF_LOG
201  * prev_lsa record is overwritten with end of log record and flushed to disk.
202  * - LOGPB_APPENDREC_PARTIAL_FLUSHED_END_OF_LOG => LOGPB_APPENDREC_PARTIAL_ENDED
203  * incomplete log record is now completely appended. logpb_flush_all_append_pages is called again.
204  * - LOGPB_APPENDREC_PARTIAL_ENDED => LOGPB_APPENDREC_PARTIAL_FLUSHED_ORIGINAL
205  * at the end of last flush, the prev_lsa record is restored and its page is flushed again to disk.
206  * - LOGPB_APPENDREC_PARTIAL_FLUSHED_ORIGINAL => LOGPB_APPENDREC_SUCCESS
207  * set the normal state of log record successful append.
208  */
209 typedef enum
210 {
211  LOGPB_APPENDREC_IN_PROGRESS, /* append record started */
212 
213  /* only for partial appended record flush: */
214  LOGPB_APPENDREC_PARTIAL_FLUSHED_END_OF_LOG, /* when flush is forced and record is not fully appended, it is
215  * replaced with end of log and its header page is flushed. */
216  LOGPB_APPENDREC_PARTIAL_ENDED, /* all record has been successfully appended */
217  LOGPB_APPENDREC_PARTIAL_FLUSHED_ORIGINAL, /* original header page is flushed */
218 
219  LOGPB_APPENDREC_SUCCESS /* finished appending record (in a stable way) */
221 
222 /* used to handle records partially written when logpb_flush_all_append_pages is forced */
225 {
227 
228  char buffer_log_page[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
232 };
233 
234 /* Global structure to trantable, log buffer pool, etc */
237 {
238  LOG_BUFFER *buffers; /* Log buffer pool */
242  int num_buffers; /* Number of log buffers */
243 
245 };
246 
247 typedef struct arv_page_info
248 {
249  int arv_num;
252 } ARV_PAGE_INFO;
253 
254 typedef struct
255 {
257  int rear;
260 
261 
262 #define LOG_MAX_LOGINFO_LINE (PATH_MAX * 4)
263 
264 /* skip prompting for archive log location */
265 #if defined(SERVER_MODE)
267 #else
269 #endif
270 
272 
275 
276 static bool logpb_Initialized = false;
277 static bool logpb_Logging = false;
278 
279 /*
280  * Functions
281  */
282 
284 static bool logpb_is_dirty (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr);
285 #if !defined(NDEBUG)
286 static bool logpb_is_any_dirty (THREAD_ENTRY * thread_p);
287 #endif /* !NDEBUG */
288 #if defined(CUBRID_DEBUG)
289 static bool logpb_is_any_fix (THREAD_ENTRY * thread_p);
290 #endif /* CUBRID_DEBUG */
291 static void logpb_dump_information (FILE * out_fp);
292 static void logpb_dump_to_flush_page (FILE * out_fp);
293 static void logpb_dump_pages (FILE * out_fp);
294 static void logpb_initialize_backup_info (LOG_HEADER * loghdr);
295 static LOG_PAGE **logpb_writev_append_pages (THREAD_ENTRY * thread_p, LOG_PAGE ** to_flush, DKNPAGES npages);
297 static void logpb_set_unavailable_archive (THREAD_ENTRY * thread_p, int arv_num);
298 static void logpb_dismount_log_archive (THREAD_ENTRY * thread_p);
299 static bool logpb_is_archive_available (THREAD_ENTRY * thread_p, int arv_num);
300 static void logpb_archive_active_log (THREAD_ENTRY * thread_p);
301 static int logpb_remove_archive_logs_internal (THREAD_ENTRY * thread_p, int first, int last, const char *info_reason);
302 static void logpb_append_archives_removed_to_log_info (int first, int last, const char *info_reason);
303 static int logpb_verify_length (const char *db_fullname, const char *log_path, const char *log_prefix);
304 static int logpb_backup_for_volume (THREAD_ENTRY * thread_p, VOLID volid, LOG_LSA * chkpt_lsa,
305  FILEIO_BACKUP_SESSION * session, bool only_updated);
306 static int logpb_update_backup_volume_info (const char *bkupinfo_file_name);
307 static int logpb_start_where_path (const char *to_db_fullname, const char *toext_path, const char **toext_name,
308  char **ext_path, char **alloc_extpath, const char *fileof_vols_and_wherepaths,
309  FILE ** where_paths_fp);
310 static int logpb_next_where_path (const char *to_db_fullname, const char *toext_path, const char *ext_name,
311  char *ext_path, const char *fileof_vols_and_wherepaths, FILE * where_paths_fp,
312  int num_perm_vols, VOLID volid, char *from_volname, char *to_volname);
313 static int logpb_copy_volume (THREAD_ENTRY * thread_p, VOLID from_volid, const char *tonew_volname, INT64 * db_creation,
314  LOG_LSA * vol_chkpt_lsa);
315 static bool logpb_check_if_exists (const char *fname, char *first_vol);
316 #if defined(SERVER_MODE)
317 static int logpb_backup_needed_archive_logs (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session,
318  int first_arv_num, int last_arv_num);
319 #endif /* SERVER_MODE */
320 static bool logpb_remote_ask_user_before_delete_volumes (THREAD_ENTRY * thread_p, const char *volpath);
321 static int logpb_initialize_flush_info (void);
322 static void logpb_finalize_flush_info (void);
323 static void logpb_finalize_writer_info (void);
324 static void logpb_dump_log_header (FILE * outfp);
325 static void logpb_dump_parameter (FILE * outfp);
326 static void logpb_dump_runtime (FILE * outfp);
327 static void logpb_initialize_log_buffer (LOG_BUFFER * log_buffer_p, LOG_PAGE * log_pg);
328 
329 static int logpb_check_stop_at_time (FILEIO_BACKUP_SESSION * session, time_t stop_at, time_t backup_time);
330 static void logpb_write_toflush_pages_to_archive (THREAD_ENTRY * thread_p);
331 static int logpb_add_archive_page_info (THREAD_ENTRY * thread_p, int arv_num, LOG_PAGEID start_page,
332  LOG_PAGEID end_page);
333 static int logpb_get_archive_num_from_info_table (THREAD_ENTRY * thread_p, LOG_PAGEID page_id);
334 
335 static int logpb_flush_all_append_pages (THREAD_ENTRY * thread_p);
336 static int logpb_append_next_record (THREAD_ENTRY * thread_p, LOG_PRIOR_NODE * ndoe);
337 
338 static void logpb_start_append (THREAD_ENTRY * thread_p, LOG_RECORD_HEADER * header);
339 static void logpb_end_append (THREAD_ENTRY * thread_p, LOG_RECORD_HEADER * header);
340 static void logpb_append_data (THREAD_ENTRY * thread_p, int length, const char *data);
341 static void logpb_append_crumbs (THREAD_ENTRY * thread_p, int num_crumbs, const LOG_CRUMB * crumbs);
342 static void logpb_next_append_page (THREAD_ENTRY * thread_p, LOG_SETDIRTY current_setdirty);
344 static int logpb_append_prior_lsa_list (THREAD_ENTRY * thread_p, LOG_PRIOR_NODE * list);
345 static int logpb_copy_page (THREAD_ENTRY * thread_p, LOG_PAGEID pageid, LOG_CS_ACCESS_MODE access_mode,
346  LOG_PAGE * log_pgptr);
347 
348 static void logpb_fatal_error_internal (THREAD_ENTRY * thread_p, bool log_exit, bool need_flush, const char *file_name,
349  const int lineno, const char *fmt, va_list ap);
350 
351 static int logpb_copy_log_header (THREAD_ENTRY * thread_p, LOG_HEADER * to_hdr, const LOG_HEADER * from_hdr);
354 static int logpb_fetch_header_from_active_log (THREAD_ENTRY * thread_p, const char *db_fullname,
355  const char *logpath, const char *prefix_logname, LOG_HEADER * hdr,
356  LOG_PAGE * log_pgptr);
357 static int logpb_compute_page_checksum (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, int *checksum_crc32);
358 static int logpb_page_has_valid_checksum (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, bool * has_valid_checksum);
359 
360 static bool logpb_is_log_active_from_backup_useful (THREAD_ENTRY * thread_p, const char *active_log_path,
361  const char *db_full_name);
362 static int logpb_peek_header_of_active_log_from_backup (THREAD_ENTRY * thread_p, const char *active_log_path,
363  LOG_HEADER * hdr);
364 
365 /*
366  * FUNCTIONS RELATED TO LOG BUFFERING
367  *
368  */
369 
370 /*
371  * logpb_get_log_buffer_index - get the current index in the log buffer
372  * return: index number
373  * log_pageid (in) : the pageid number
374  */
375 STATIC_INLINE int
377 {
378  return log_pageid % log_Pb.num_buffers;
379 }
380 
381 /*
382  * logpb_get_log_buffer - get the buffer from the log page
383  * return: the coresponding buffer
384  * log_pg (in) : the log page
385  * NOTE: the function finds the index of the log page and returns
386  * the coresponding buffer
387  */
390 {
391  int index;
392 
393  if (log_pg == log_Pb.header_page)
394  {
395  return &log_Pb.header_buffer;
396  }
397 
398  assert ((UINT64) ((char *) log_pg - (char *) log_Pb.pages_area) / LOG_PAGESIZE < INT_MAX);
399  index = (int) ((UINT64) ((char *) log_pg - (char *) log_Pb.pages_area) / LOG_PAGESIZE);
400 
401  /* Safe guard: index is valid. */
402  assert (index >= 0 && index < log_Pb.num_buffers);
403  /* Safe guard: log_pg is correctly aligned. */
404  assert ((char *) log_Pb.pages_area + (UINT64) LOG_PAGESIZE * index == (char *) log_pg);
405 
406  return &log_Pb.buffers[index];
407 }
408 
409 /*
410  * logpb_initialize_log_buffer -
411  *
412  * return: nothing
413  *
414  * log_buffer_p(in/oiut):
415  *
416  * NOTE:
417  *
418  */
419 static void
421 {
422  log_buffer_p->pageid = NULL_PAGEID;
423  log_buffer_p->phy_pageid = NULL_PAGEID;
424  log_buffer_p->dirty = false;
425  log_buffer_p->logpage = log_pg;
426  log_buffer_p->logpage->hdr.logical_pageid = NULL_PAGEID;
427  log_buffer_p->logpage->hdr.offset = NULL_OFFSET;
428  log_buffer_p->logpage->hdr.flags = 0;
429 }
430 
431 /*
432  * logpb_compute_page_checksum - Computes log page checksum.
433  * return: error code
434  * thread_p (in) : thread entry
435  * log_pgptr (in) : log page pointer
436  * checksum_crc32(out): computed checksum
437  * Note: Currently CRC32 is used as checksum.
438  * Note: any changes to this requires changes to logwr_check_page_checksum
439  */
440 static int
441 logpb_compute_page_checksum (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, int *checksum_crc32)
442 {
443  int error_code = NO_ERROR, saved_checksum_crc32;
444  const int block_size = 4096;
445  const int max_num_pages = IO_MAX_PAGE_SIZE / block_size;
446  const int sample_nbytes = 16;
447  int sampling_offset;
448  char buf[max_num_pages * sample_nbytes * 2];
449  const int num_pages = LOG_PAGESIZE / block_size;
450  const size_t sizeof_buf = num_pages * sample_nbytes * 2;
451 
452  assert (log_pgptr != NULL && checksum_crc32 != NULL);
453 
454  /* Save the old page checksum. */
455  saved_checksum_crc32 = log_pgptr->hdr.checksum;
456 
457  /* Resets checksum to not affect the new computation. */
458  log_pgptr->hdr.checksum = 0;
459 
460  char *p = buf;
461  for (int i = 0; i < num_pages; i++)
462  {
463  // first
464  sampling_offset = (i * block_size);
465  memcpy (p, ((char *) log_pgptr) + sampling_offset, sample_nbytes);
466  p += sample_nbytes;
467 
468  // last
469  sampling_offset = (i * block_size) + (block_size - sample_nbytes);
470  memcpy (p, ((char *) log_pgptr) + sampling_offset, sample_nbytes);
471  p += sample_nbytes;
472  }
473 
474  crypt_crc32 ((char *) buf, (int) sizeof_buf, checksum_crc32);
475 
476  /* Restores the saved checksum */
477  log_pgptr->hdr.checksum = saved_checksum_crc32;
478 
479  return error_code;
480 }
481 
482 /*
483  * logpb_set_page_checksum - Set log page checksum.
484  * return: error code
485  * thread_p (in) : thread entry
486  * log_pgptr (in) : log page pointer
487  * Note: Currently CRC32 is used as checksum.
488  */
489 int
491 {
492  int error_code = NO_ERROR, checksum_crc32;
493 
494  assert (log_pgptr != NULL);
495 
496  /* Computes the page checksum. */
497  error_code = logpb_compute_page_checksum (thread_p, log_pgptr, &checksum_crc32);
498  if (error_code != NO_ERROR)
499  {
500  return error_code;
501  }
502 
503  log_pgptr->hdr.checksum = checksum_crc32;
504  logpb_log ("logpb_set_page_checksum: log page %lld has checksum = %d\n",
505  (long long int) log_pgptr->hdr.logical_pageid, checksum_crc32);
506 
507  return NO_ERROR;
508 }
509 
510 /*
511  * logpb_page_has_valid_checksum - Check whether the log page checksum is valid.
512  * return: error code
513  * thread_p(in): thread entry
514  * log_pgptr(in): the log page
515  * has_valid_checksum(out): true, if has valid checksum.
516  */
517 static int
518 logpb_page_has_valid_checksum (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, bool * has_valid_checksum)
519 {
520  int checksum_crc32, error_code = NO_ERROR;
521 
522  assert (log_pgptr != NULL && has_valid_checksum != NULL);
523 
524  error_code = logpb_compute_page_checksum (thread_p, log_pgptr, &checksum_crc32);
525  if (error_code != NO_ERROR)
526  {
527  return error_code;
528  }
529 
530  *has_valid_checksum = (checksum_crc32 == log_pgptr->hdr.checksum);
531  if (*has_valid_checksum == false)
532  {
533  logpb_log ("logpb_page_has_valid_checksum: log page %lld has checksum = %d, computed checksum = %d\n",
534  (long long int) log_pgptr->hdr.logical_pageid, log_pgptr->hdr.checksum, checksum_crc32);
535  }
536 
537  return NO_ERROR;
538 }
539 
540 /*
541  * logpb_initialize_pool - Initialize the log buffer pool
542  *
543  * return: NO_ERROR if all OK, ER_ status otherwise
544  *
545  * NOTE:Initialize the log buffer pool. All resident pages are invalidated.
546  */
547 int
549 {
550  int error_code = NO_ERROR;
551  int i;
552  LOG_GROUP_COMMIT_INFO *group_commit_info = &log_Gl.group_commit_info;
553  LOGWR_INFO *writer_info = log_Gl.writer_info;
554  size_t size;
555 
556  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
557 
559 
560  if (logpb_Initialized == true)
561  {
562  logpb_finalize_pool (thread_p);
563  }
564 
565  assert (log_Pb.pages_area == NULL);
566  assert (logpb_Initialized == false);
567 
569 
570  /*
571  * Create an area to keep the number of desired buffers
572  */
574 
575  /* allocate a pointer array to point to each buffer */
576  size = ((size_t) log_Pb.num_buffers * sizeof (*log_Pb.buffers));
577  log_Pb.buffers = (LOG_BUFFER *) malloc (size);
578  if (log_Pb.buffers == NULL)
579  {
582  }
583 
584  size = ((size_t) log_Pb.num_buffers * (LOG_PAGESIZE));
585  log_Pb.pages_area = (LOG_PAGE *) malloc (size);
586  if (log_Pb.pages_area == NULL)
587  {
588  free_and_init (log_Pb.buffers);
591  }
592 
593  /* Initialize every new buffer */
594  memset (log_Pb.pages_area, LOG_PAGE_INIT_VALUE, size);
595  for (i = 0; i < log_Pb.num_buffers; i++)
596  {
598  (LOG_PAGE *) ((char *) log_Pb.pages_area + (UINT64) i * (LOG_PAGESIZE)));
599  }
600 
601  size = LOG_PAGESIZE;
602  log_Pb.header_page = (LOG_PAGE *) malloc (size);
603  if (log_Pb.header_page == NULL)
604  {
605  free_and_init (log_Pb.buffers);
606  free_and_init (log_Pb.pages_area);
609  }
610 
611  memset (log_Pb.header_page, LOG_PAGE_INIT_VALUE, size);
613 
614  error_code = logpb_initialize_flush_info ();
615  if (error_code != NO_ERROR)
616  {
617  goto error;
618  }
619 
620  /* Initialize partial append */
624 
625 #if !defined (NDEBUG)
626  // suppress valgrind complaint.
628 #endif // DEBUG
629 
630  logpb_Initialized = true;
631  pthread_mutex_init (&log_Gl.chkpt_lsa_lock, NULL);
632 
633  pthread_cond_init (&group_commit_info->gc_cond, NULL);
634  pthread_mutex_init (&group_commit_info->gc_mutex, NULL);
635 
636  pthread_mutex_init (&writer_info->wr_list_mutex, NULL);
637 
638  pthread_cond_init (&writer_info->flush_start_cond, NULL);
639  pthread_mutex_init (&writer_info->flush_start_mutex, NULL);
640 
641  pthread_cond_init (&writer_info->flush_wait_cond, NULL);
642  pthread_mutex_init (&writer_info->flush_wait_mutex, NULL);
643 
644  pthread_cond_init (&writer_info->flush_end_cond, NULL);
645  pthread_mutex_init (&writer_info->flush_end_mutex, NULL);
646 
647  writer_info->is_init = true;
648 
649  return error_code;
650 
651 error:
652 
653  logpb_finalize_pool (thread_p);
654  logpb_fatal_error (thread_p, false, ARG_FILE_LINE, "log_pbpool_init");
655 
656  return error_code;
657 }
658 
659 /*
660  * logpb_finalize_pool - TERMINATES THE LOG BUFFER POOL
661  *
662  * return: nothing
663  *
664  * NOTE:Terminate the log buffer pool. All log resident pages are invalidated.
665  */
666 void
668 {
670 
671  if (logpb_Initialized == false)
672  {
673  /* logpb already finalized */
674  return;
675  }
676 
677  if (log_Gl.append.log_pgptr != NULL)
678  {
680  }
683  /* copy log_Gl.append.prev_lsa to log_Gl.prior_info.prev_lsa */
685 
686 #if defined(CUBRID_DEBUG)
687  if (logpb_is_any_dirty (thread_p) == true || logpb_is_any_fix (thread_p) == true)
688  {
689  er_log_debug (ARG_FILE_LINE, "log_pbpool_final: Log Buffer pool contains dirty or fixed pages at the end.\n");
690  logpb_dump (thread_p, stdout);
691  }
692 #endif /* CUBRID_DEBUG */
693 
694  free_and_init (log_Pb.buffers);
695  free_and_init (log_Pb.pages_area);
696  free_and_init (log_Pb.header_page);
697  log_Pb.num_buffers = 0;
698  logpb_Initialized = false;
700 
701  pthread_mutex_destroy (&log_Gl.chkpt_lsa_lock);
702 
704  pthread_cond_destroy (&log_Gl.group_commit_info.gc_cond);
705 
707 
709 }
710 
711 /*
712  * logpb_is_pool_initialized - Find out if buffer pool has been initialized
713  *
714  * return:
715  *
716  * NOTE:Find out if the buffer pool has been initialized.
717  */
718 bool
720 {
722 
723  return logpb_Initialized;
724 }
725 
726 /*
727  * logpb_invalidate_pool - Invalidate all buffers in buffer pool
728  *
729  * return: Pointer to the page or NULL
730  *
731  * NOTE:Invalidate all unfixed buffers in the buffer pool.
732  * This is needed when we reset the log header information.
733  */
734 void
736 {
737  LOG_BUFFER *log_bufptr; /* A log buffer */
738  int i;
739 
740  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
741 
742  if (logpb_Initialized == false)
743  {
744  return;
745  }
746 
747  /*
748  * Flush any append dirty buffers at this moment.
749  * Then, invalidate any buffer that it is not fixed and dirty
750  */
751  logpb_flush_pages_direct (thread_p);
752 
753  for (i = 0; i < log_Pb.num_buffers; i++)
754  {
755  log_bufptr = LOGPB_FIND_BUFPTR (i);
756  if (log_bufptr->pageid != NULL_PAGEID && !log_bufptr->dirty == false)
757  {
758  logpb_initialize_log_buffer (log_bufptr, log_bufptr->logpage);
759  }
760  }
761 }
762 
763 
764 /*
765  * logpb_create_page - Create a log page on a log buffer
766  *
767  * return: Pointer to the page or NULL
768  *
769  * pageid(in): Page identifier
770  *
771  * NOTE:Creates the log page identified by pageid on a log buffer and return such buffer.
772  * Just initializes log buffer hdr,
773  * To read a page from disk is not needed.
774  */
775 LOG_PAGE *
777 {
778  return logpb_locate_page (thread_p, pageid, NEW_PAGE);
779 }
780 
781 /*
782  * logpb_locate_page - Fetch a log page
783  *
784  * return: Pointer to the page or NULL
785  *
786  * pageid(in): Page identifier
787  * fetch_mode(in): Is this a new log page ?. That is, can we avoid the I/O
788  *
789  * NOTE: first, the function checks if the pageid is the header page id.
790  * if it is not, it brings the coresponding page from the log page buffer.
791  * if the actual pageid differs from the buffer pageid, it means that it should
792  * be invalidated - it contains another page - and it is flushed to disk, if it
793  * is dirty. Now, if the pageid is null , we have a clear log page. If the fetch
794  * mode is NEW_PAGE, it set the fields in the buffer, else, if it is OLD_PAGE,
795  * it brings the page from the disk. The last case is if the page is not NULL, and
796  * it is equal with the pageid. This means it is an OLD_PAGE request, and it returns
797  * that page.
798  */
799 static LOG_PAGE *
801 {
802  LOG_BUFFER *log_bufptr = NULL; /* A log buffer */
803  LOG_PHY_PAGEID phy_pageid = NULL_PAGEID; /* The corresponding physical page */
804  bool is_perf_tracking;
805  TSC_TICKS start_tick, end_tick;
806  TSCTIMEVAL tv_diff;
807  UINT64 fix_wait_time;
809  int index;
810 
811  logpb_log ("called logpb_locate_page for pageid %lld, fetch_mode=%s", (long long int) pageid,
812  fetch_mode == NEW_PAGE ? "new_page" : "old_page\n");
813 
814  is_perf_tracking = perfmon_is_perf_tracking ();
815  if (is_perf_tracking)
816  {
817  tsc_getticks (&start_tick);
818  }
819 
820  assert (pageid != NULL_PAGEID);
821  assert ((fetch_mode == NEW_PAGE) || (fetch_mode == OLD_PAGE));
822  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
823 
824  if (pageid == LOGPB_HEADER_PAGE_ID)
825  {
826  log_bufptr = &log_Pb.header_buffer;
827  }
828  else
829  {
830  index = logpb_get_log_buffer_index ((int) pageid);
831  if (index >= 0 && index < log_Pb.num_buffers)
832  {
833  log_bufptr = &log_Pb.buffers[index];
834  }
835  else
836  {
838  return NULL;
839  }
840 
841  }
842  assert (log_bufptr != NULL);
843 
844  if (log_bufptr->pageid != NULL_PAGEID && log_bufptr->pageid != pageid)
845  {
846  if (log_bufptr->dirty == true)
847  {
848  /* should not happen */
849  assert_release (false);
850  logpb_log ("logpb_locate_page: fatal error, victimizing dirty log page %lld.\n",
851  (long long int) log_bufptr->pageid);
852 
853  if (logpb_write_page_to_disk (thread_p, log_bufptr->logpage, log_bufptr->pageid) != NO_ERROR)
854  {
855  assert_release (false);
856  return NULL;
857  }
858  log_bufptr->dirty = false;
860  }
861 
862  log_bufptr->pageid = NULL_PAGEID; /* invalidate buffer */
864  }
865 
866  if (log_bufptr->pageid == NULL_PAGEID)
867  {
868  if (fetch_mode == NEW_PAGE)
869  {
870  /* Fills log page with 0xff, for checksum consistency. */
871  memset (log_bufptr->logpage, LOG_PAGE_INIT_VALUE, LOG_PAGESIZE);
872  log_bufptr->logpage->hdr.logical_pageid = pageid;
873  log_bufptr->logpage->hdr.offset = NULL_OFFSET;
874  log_bufptr->logpage->hdr.flags = 0;
875  }
876  else
877  {
878  stat_page_found = PERF_PAGE_MODE_OLD_LOCK_WAIT;
879  if (logpb_read_page_from_file (thread_p, pageid, LOG_CS_FORCE_USE, log_bufptr->logpage) != NO_ERROR)
880  {
881  return NULL;
882  }
883  }
884  phy_pageid = logpb_to_physical_pageid (pageid);
885  log_bufptr->phy_pageid = phy_pageid;
886  log_bufptr->pageid = pageid;
887  }
888  else
889  {
890  assert (fetch_mode == OLD_PAGE);
891  assert (log_bufptr->pageid == pageid);
892  logpb_log ("logpb_locate_page using log buffer entry for pageid = %lld", pageid);
893  }
894 
896  if (is_perf_tracking)
897  {
898  tsc_getticks (&end_tick);
899  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
900  fix_wait_time = tv_diff.tv_sec * 1000000LL + tv_diff.tv_usec;
901  if (fix_wait_time > 0)
902  {
903  perfmon_pbx_fix_acquire_time (thread_p, PAGE_LOG, stat_page_found, PERF_HOLDER_LATCH_READ,
904  PERF_UNCONDITIONAL_FIX_WITH_WAIT, fix_wait_time);
905  }
906  }
907 
908  ASSERT_ALIGN (log_bufptr->logpage->area, MAX_ALIGNMENT);
909  return log_bufptr->logpage;
910 }
911 
912 /*
913  * logpb_set_dirty - Mark the current page dirty
914  *
915  * return: nothing
916  *
917  * log_pgptr(in): Log page pointer
918  *
919  * NOTE:Mark the current log page as dirty.
920  */
921 void
922 logpb_set_dirty (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr)
923 {
924  LOG_BUFFER *bufptr; /* Log buffer associated with given page */
925 
926  /* Get the address of the buffer from the page. */
927  bufptr = logpb_get_log_buffer (log_pgptr);
928  if (!bufptr->dirty)
929  {
930  logpb_log ("dirty flag set for pageid = %lld\n", (long long int) bufptr->pageid);
931  }
932 #if defined(CUBRID_DEBUG)
933  if (bufptr->pageid != LOGPB_HEADER_PAGE_ID
935  {
937  }
938 #endif /* CUBRID_DEBUG */
939 
940  bufptr->dirty = true;
941 }
942 
943 /*
944  * logpb_is_dirty - Find if current log page pointer is dirty
945  *
946  * return:
947  *
948  * log_pgptr(in): Log page pointer
949  *
950  * NOTE:Find if the current log page is dirty.
951  */
952 static bool
953 logpb_is_dirty (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr)
954 {
955  LOG_BUFFER *bufptr; /* Log buffer associated with given page */
956  bool is_dirty;
957 
958  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
959 
960  /* Get the address of the buffer from the page. */
961  bufptr = logpb_get_log_buffer (log_pgptr);
962  is_dirty = (bool) bufptr->dirty;
963 
964  return is_dirty;
965 }
966 
967 #if !defined(NDEBUG)
968 /*
969  * logpb_is_any_dirty - FIND IF ANY LOG BUFFER IS DIRTY
970  *
971  * return:
972  *
973  * NOTE:Find if any log buffer is dirty.
974  */
975 static bool
977 {
978  LOG_BUFFER *bufptr; /* A log buffer */
979  int i;
980  bool ret;
981 
982  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
983 
984  ret = false;
985  for (i = 0; i < log_Pb.num_buffers; i++)
986  {
987  bufptr = LOGPB_FIND_BUFPTR (i);
988  if (bufptr->dirty == true)
989  {
990  ret = true;
991  break;
992  }
993  }
994 
995  return ret;
996 }
997 #endif /* !NDEBUG || CUBRID_DEBUG */
998 
999 #if defined(CUBRID_DEBUG)
1000 /*
1001  * logpb_is_any_fix - Find if any log buffer is fixed
1002  *
1003  * return:
1004  *
1005  * NOTE:Find if any buffer is fixed
1006  */
1007 static bool
1008 logpb_is_any_fix (THREAD_ENTRY * thread_p)
1009 {
1010  LOG_BUFFER *bufptr; /* A log buffer */
1011  int i, rv;
1012  bool ret;
1013 
1014  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1015 
1016  ret = false;
1017  for (i = 0; i < log_Pb.num_buffers; i++)
1018  {
1019  bufptr = LOGPB_FIND_BUFPTR (i);
1020  if (bufptr->pageid != NULL_PAGEID)
1021  {
1022  ret = true;
1023  break;
1024  }
1025  }
1026 
1027  return ret;
1028 }
1029 #endif /* CUBRID_DEBUG */
1030 
1031 /*
1032  * logpb_flush_page - Flush a page of the active portion of the log to disk
1033  *
1034  * return: nothing
1035  *
1036  * log_pgptr(in): Log page pointer
1037  *
1038  * NOTE:The log page (of the active portion of the log) associated
1039  * with pageptr is written out to disk and is optionally freed.
1040  */
1041 int
1042 logpb_flush_page (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr)
1043 {
1044  LOG_BUFFER *bufptr; /* Log buffer associated with given page */
1045 
1046  /* Get the address of the buffer from the page. */
1047  bufptr = logpb_get_log_buffer (log_pgptr);
1048 
1049  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1050 
1051  logpb_log ("called logpb_flush_page for pageid = %lld\n", (long long int) bufptr->pageid);
1052 
1053 #if defined(CUBRID_DEBUG)
1054  if (bufptr->pageid != LOGPB_HEADER_PAGE_ID
1056  {
1059  }
1060  if (bufptr->phy_pageid == NULL_PAGEID || bufptr->phy_pageid != logpb_to_physical_pageid (bufptr->pageid))
1061  {
1062  /* Bad physical log page for such logical page */
1064  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "logpb_flush_page");
1065  return ER_LOG_PAGE_CORRUPTED;
1066  }
1067 #endif /* CUBRID_DEBUG */
1068 
1069  if (bufptr->dirty == true)
1070  {
1071  /*
1072  * The buffer is dirty, flush it
1073  */
1074 
1075  /*
1076  * Even when the log has been open with the o_sync option, force a sync
1077  * since some Operationg system (HP) seems that does not have the effect
1078  * of forcing the page to disk without doing fync
1079  */
1080 
1081  if (logpb_write_page_to_disk (thread_p, log_pgptr, bufptr->pageid) != NO_ERROR)
1082  {
1083  goto error;
1084  }
1085  else
1086  {
1087  bufptr->dirty = false;
1088  }
1089  }
1090 
1091  return NO_ERROR;
1092 
1093 error:
1094 
1095  return ER_FAILED;
1096 }
1097 
1098 /*
1099  * logpb_get_page_id - Logical pageid of log buffer/page
1100  *
1101  * return: pageid
1102  *
1103  * log_pgptr(in): Log page pointer
1104  *
1105  * NOTE:The page identifier of the given log page/buffer.
1106  * The page is always fix when this funtion is called.
1107  * In replacement, the page cannot be replaced because fix > 0.
1108  * So, it isn't needed to lock mutex.
1109  */
1110 LOG_PAGEID
1112 {
1113  LOG_BUFFER *bufptr; /* Log buffer associated with given page */
1114 
1115  bufptr = logpb_get_log_buffer (log_pgptr);
1116 
1117  return bufptr->pageid;
1118 }
1119 
1120 /*
1121  * logpb_dump - DUMP THE LOG PAGE BUFFER POOL
1122  *
1123  * return: nothing
1124  *
1125  * NOTE:Dump the log page buffer pool. This function is used for debugging purposes.
1126  */
1127 void
1128 logpb_dump (THREAD_ENTRY * thread_p, FILE * out_fp)
1129 {
1130  if (logpb_Initialized == false)
1131  {
1132  return;
1133  }
1134 
1135  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1136 
1137  logpb_dump_information (out_fp);
1138 
1139  if (log_Gl.flush_info.num_toflush > 0)
1140  {
1141  logpb_dump_to_flush_page (out_fp);
1142  }
1143 
1144  (void) fprintf (out_fp, "\n\n");
1145  (void) fprintf (out_fp, "Buf Log_Pageid Phy_pageid Drt Rct Bufaddr Pagearea HDR:Pageid offset\n");
1146 
1147  logpb_dump_pages (out_fp);
1148 }
1149 
1150 /*
1151  * logpb_dump_information -
1152  *
1153  * return: nothing
1154  *
1155  * NOTE:
1156  */
1157 static void
1158 logpb_dump_information (FILE * out_fp)
1159 {
1160  long long int append;
1161  int i;
1162 
1163  fprintf (out_fp, "\n\n ** DUMP OF LOG BUFFER POOL INFORMATION **\n\n");
1164 
1165  fprintf (out_fp, "\nHash table dump\n");
1166  for (i = 0; i < log_Pb.num_buffers; i++)
1167  {
1168  fprintf (out_fp, "Pageid = %5lld, Address = %p\n", (long long int) i, (void *) &log_Pb.buffers[i]);
1169  }
1170  fprintf (out_fp, "\n\n");
1171 
1172  fprintf (out_fp, " Next IO_LSA = %lld|%d, Current append LSA = %lld|%d, Prev append LSA = %lld|%d\n"
1173  " Prior LSA = %lld|%d, Prev prior LSA = %lld|%d\n\n",
1174  (long long int) log_Gl.append.get_nxio_lsa ().pageid, (int) log_Gl.append.get_nxio_lsa ().offset,
1175  (long long int) log_Gl.hdr.append_lsa.pageid, (int) log_Gl.hdr.append_lsa.offset,
1176  (long long int) log_Gl.append.prev_lsa.pageid, (int) log_Gl.append.prev_lsa.offset,
1178  (long long int) log_Gl.prior_info.prev_lsa.pageid, (int) log_Gl.prior_info.prev_lsa.offset);
1179 
1180  if (log_Gl.append.log_pgptr == NULL)
1181  {
1182  append = NULL_PAGEID;
1183  }
1184  else
1185  {
1187  }
1188 
1189  fprintf (out_fp, " Append to_flush array: max = %d, num_active = %d\n"
1190  " Current append page = %lld\n", log_Gl.flush_info.max_toflush, log_Gl.flush_info.num_toflush, append);
1191 }
1192 
1193 /*
1194  * logpb_dump_to_flush_page -
1195  *
1196  * return: nothing
1197  *
1198  * NOTE:
1199  */
1200 static void
1202 {
1203  int i;
1204  LOG_BUFFER *log_bufptr;
1205  LOG_FLUSH_INFO *flush_info = &log_Gl.flush_info;
1206 
1207  (void) fprintf (out_fp, " Candidate append pages to flush are:\n");
1208 
1209  for (i = 0; i < flush_info->num_toflush; i++)
1210  {
1211  log_bufptr = logpb_get_log_buffer (flush_info->toflush[i]);
1212  if (i != 0)
1213  {
1214  if ((i % 10) == 0)
1215  {
1216  fprintf (out_fp, ",\n");
1217  }
1218  else
1219  {
1220  fprintf (out_fp, ",");
1221  }
1222  }
1223  fprintf (out_fp, " %4lld", (long long int) log_bufptr->pageid);
1224  }
1225 
1226  fprintf (out_fp, "\n");
1227 }
1228 
1229 /*
1230  * logpb_dump_pages -
1231  *
1232  * return: nothing
1233  *
1234  * NOTE:
1235  */
1236 static void
1237 logpb_dump_pages (FILE * out_fp)
1238 {
1239  int i;
1240  LOG_BUFFER *log_bufptr;
1241 
1242  for (i = 0; i < log_Pb.num_buffers; i++)
1243  {
1244  log_bufptr = LOGPB_FIND_BUFPTR (i);
1245  if (log_bufptr->pageid == NULL_PAGEID)
1246  {
1247  /* *** ** (void)fprintf(stdout, "%3d ..\n", i); */
1248  continue;
1249  }
1250  else
1251  {
1252  fprintf (out_fp, "%3d %10lld %10d %3d %p %p-%p %4s %5lld %5d\n",
1253  i, (long long) log_bufptr->pageid, log_bufptr->phy_pageid, log_bufptr->dirty,
1254  (void *) log_bufptr, (void *) (log_bufptr->logpage),
1255  (void *) (&log_bufptr->logpage->area[LOGAREA_SIZE - 1]), "",
1256  (long long) log_bufptr->logpage->hdr.logical_pageid, log_bufptr->logpage->hdr.offset);
1257  }
1258  }
1259  fprintf (out_fp, "\n");
1260 }
1261 
1262 /*
1263  * logpb_initialize_backup_info - initialized backup information
1264  *
1265  * return: nothing
1266  *
1267  * NOTE:
1268  */
1269 static void
1271 {
1272  int i;
1273 
1274  for (i = 0; i < FILEIO_BACKUP_UNDEFINED_LEVEL; i++)
1275  {
1276  log_hdr->bkinfo[i].ndirty_pages_post_bkup = 0;
1277  log_hdr->bkinfo[i].io_baseln_time = 0;
1278  log_hdr->bkinfo[i].io_numpages = 0;
1279  log_hdr->bkinfo[i].io_bkuptime = 0;
1280  }
1281 }
1282 
1283 /*
1284  * logpb_initialize_header - Initialize log header structure
1285  *
1286  * return: nothing
1287  *
1288  * loghdr(in/out): Log header structure
1289  * prefix_logname(in): Name of the log volumes. It is usually set the same as
1290  * database name. For example, if the value is equal to
1291  * "db", the names of the log volumes created are as
1292  * follow:
1293  * Active_log = db_logactive
1294  * Archive_logs = db_logarchive.0
1295  * db_logarchive.1
1296  * .
1297  * .
1298  * .
1299  * db_logarchive.n
1300  * Log_information = db_loginfo
1301  * Database Backup = db_backup
1302  * npages(in): Size of active log in pages
1303  * db_creation(in): Database creation time.
1304  *
1305  * NOTE:Initialize a log header structure.
1306  */
1307 int
1308 logpb_initialize_header (THREAD_ENTRY * thread_p, LOG_HEADER * loghdr, const char *prefix_logname,
1309  DKNPAGES npages, INT64 * db_creation)
1310 {
1311  int i;
1312 
1313  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1314  assert (loghdr != NULL);
1315 
1316  /* to also initialize padding bytes */
1317  memset (loghdr, 0, sizeof (LOG_HEADER));
1318 
1320 
1321  if (db_creation != NULL)
1322  {
1323  loghdr->db_creation = *db_creation;
1324  }
1325  else
1326  {
1327  loghdr->db_creation = -1;
1328  }
1329 
1331  {
1334  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_init_logheader");
1336  }
1337 
1340  loghdr->db_iopagesize = IO_PAGESIZE;
1341  loghdr->db_logpagesize = LOG_PAGESIZE;
1342  loghdr->is_shutdown = true;
1343  loghdr->next_trid = LOG_SYSTEM_TRANID + 1;
1344  loghdr->mvcc_next_id = MVCCID_FIRST;
1347  loghdr->npages = npages - 1; /* Hdr pg is stolen */
1348  loghdr->db_charset = lang_charset ();
1349  loghdr->fpageid = 0;
1350  loghdr->append_lsa.pageid = loghdr->fpageid;
1351  loghdr->append_lsa.offset = 0;
1352  LSA_COPY (&loghdr->chkpt_lsa, &loghdr->append_lsa);
1353  loghdr->nxarv_pageid = loghdr->fpageid;
1354  loghdr->nxarv_phy_pageid = 1;
1355  loghdr->nxarv_num = 0;
1356  loghdr->last_arv_num_for_syscrashes = -1;
1357  loghdr->last_deleted_arv_num = -1;
1358  loghdr->has_logging_been_skipped = false;
1359  LSA_SET_NULL (&loghdr->bkup_level0_lsa);
1360  LSA_SET_NULL (&loghdr->bkup_level1_lsa);
1361  LSA_SET_NULL (&loghdr->bkup_level2_lsa);
1362  if (prefix_logname != NULL)
1363  {
1364  strcpy (loghdr->prefix_name, prefix_logname);
1365  }
1366  else
1367  {
1368  loghdr->prefix_name[0] = '\0';
1369  }
1370  loghdr->vacuum_last_blockid = 0;
1371  loghdr->perm_status_obsolete = 0;
1372 
1373  for (i = 0; i < FILEIO_BACKUP_UNDEFINED_LEVEL; i++)
1374  {
1375  loghdr->bkinfo[i].bkup_attime = 0;
1376  }
1378 
1380  loghdr->ha_file_status = -1;
1381  LSA_SET_NULL (&loghdr->eof_lsa);
1383 
1384  logpb_vacuum_reset_log_header_cache (thread_p, loghdr);
1385 
1386  return NO_ERROR;
1387 }
1388 
1389 /*
1390  * logpb_create_header_page - Create log header page
1391  *
1392  * return: Pointer to the page or NULL
1393  *
1394  * NOTE:Create the log header page.
1395  */
1396 LOG_PAGE *
1398 {
1399  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1400 
1401  return logpb_create_page (thread_p, LOGPB_HEADER_PAGE_ID);
1402 }
1403 
1404 /*
1405  * logpb_copy_log_header - Copy a log header
1406  *
1407  * return: NO_ERROR if all OK
1408  *
1409  * to_hdr(in): New log header
1410  * from_hdr(in): Source log header
1411  *
1412  * NOTE: Copy a log header.
1413  */
1414 static int
1415 logpb_copy_log_header (THREAD_ENTRY * thread_p, LOG_HEADER * to_hdr, const LOG_HEADER * from_hdr)
1416 {
1417  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1418  assert (to_hdr != NULL);
1419  assert (from_hdr != NULL);
1420 
1421  to_hdr->was_copied = true; // should be reset on first restart
1422 
1423  to_hdr->mvcc_next_id = from_hdr->mvcc_next_id;
1424 
1425  /* Add other attributes that need to be copied */
1426 
1427  return NO_ERROR;
1428 }
1429 
1430 /*
1431  * logpb_fetch_header - Fetch log header
1432  *
1433  * return: nothing
1434  *
1435  * hdr(in/out): Pointer where log header is stored
1436  *
1437  * NOTE:Read the log header into the area pointed by hdr.
1438  */
1439 void
1441 {
1442  assert (hdr != NULL);
1443  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1445 
1447 
1448  /* sync append_lsa to prior_lsa */
1450 }
1451 
1452 /*
1453  * logpb_fetch_header_with_buffer - Fetch log header using given buffer
1454  *
1455  * return: nothing
1456  *
1457  * hdr(in/out): Pointer where log header is stored
1458  * log_pgptr(in/out): log page buffer ptr
1459  *
1460  * NOTE:Read the log header into the area pointed by hdr
1461  */
1462 void
1464 {
1465  LOG_HEADER *log_hdr; /* The log header */
1466  LOG_LSA header_lsa;
1467 
1468  assert (hdr != NULL);
1469  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1470  assert (log_pgptr != NULL);
1471 
1472  header_lsa.pageid = LOGPB_HEADER_PAGE_ID;
1473  header_lsa.offset = LOG_PAGESIZE;
1474 
1475  if ((logpb_fetch_page (thread_p, &header_lsa, LOG_CS_SAFE_READER, log_pgptr)) != NO_ERROR)
1476  {
1477  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_fetch_hdr_with_buf");
1478  /* This statement should not be reached */
1479  (void) logpb_initialize_header (thread_p, hdr, NULL, 0, NULL);
1480  return;
1481  }
1482 
1483  log_hdr = (LOG_HEADER *) (log_pgptr->area);
1484  *hdr = *log_hdr;
1485 
1487  assert (log_pgptr->hdr.offset == NULL_OFFSET);
1488 }
1489 
1490 /*
1491  * logpb_fetch_header_from_active_log - Fetch log header directly from active log file
1492  *
1493  * return: error code
1494  *
1495  * hdr(in/out): Pointer where log header is stored
1496  * log_pgptr(in/out): log page buffer ptr
1497  *
1498  * NOTE: Should be used only during boot sequence.
1499  */
1500 static int
1501 logpb_fetch_header_from_active_log (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
1502  const char *prefix_logname, LOG_HEADER * hdr, LOG_PAGE * log_pgptr)
1503 {
1504  LOG_HEADER *log_hdr; /* The log header */
1506  int error_code = NO_ERROR;
1507 
1508  assert (db_fullname != NULL);
1509  assert (logpath != NULL);
1510  assert (prefix_logname != NULL);
1511  assert (hdr != NULL);
1512  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1513  assert (log_pgptr != NULL);
1514 
1515  error_code = logpb_initialize_log_names (thread_p, db_fullname, logpath, prefix_logname);
1516  if (error_code != NO_ERROR)
1517  {
1518  goto error;
1519  }
1520 
1521  if (fileio_is_volume_exist (log_Name_active) == false)
1522  {
1523  error_code = ER_FAILED;
1524  goto error;
1525  }
1526 
1527  log_Gl.append.vdes = fileio_mount (thread_p, db_fullname, log_Name_active, LOG_DBLOG_ACTIVE_VOLID, true, false);
1528  if (log_Gl.append.vdes == NULL_VOLDES)
1529  {
1530  error_code = ER_FAILED;
1531  goto error;
1532  }
1533 
1535  logpb_log ("reading from active log:%s, physical page is : %lld\n", log_Name_active, (long long int) phy_pageid);
1536 
1537  if (fileio_read (thread_p, log_Gl.append.vdes, log_pgptr, phy_pageid, LOG_PAGESIZE) == NULL)
1538  {
1540  log_Name_active);
1541  error_code = ER_LOG_READ;
1542  goto error;
1543  }
1544 
1545  log_hdr = (LOG_HEADER *) (log_pgptr->area);
1546  *hdr = *log_hdr;
1547 
1548  /* keep active log mounted : this prevents other process to access/change DB parameters */
1549 
1550  if (log_pgptr->hdr.logical_pageid != LOGPB_HEADER_PAGE_ID || log_pgptr->hdr.offset != NULL_OFFSET)
1551  {
1553  error_code = ER_LOG_PAGE_CORRUPTED;
1554  goto error;
1555  }
1556 
1557 #if !defined(NDEBUG)
1559  {
1560  logpb_debug_check_log_page (thread_p, log_pgptr);
1561  }
1562 #endif
1563 
1564 error:
1565  return error_code;
1566 }
1567 
1568 // it peeks header page of the backuped log active file
1569 static int
1570 logpb_peek_header_of_active_log_from_backup (THREAD_ENTRY * thread_p, const char *active_log_path, LOG_HEADER * hdr)
1571 {
1572  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
1573  LOG_HEADER *log_hdr;
1575  int error_code = NO_ERROR;
1576  LOG_PAGE *log_pgptr;
1577 
1578  assert (active_log_path != NULL);
1579  assert (hdr != NULL);
1580 
1581  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
1582 
1583  if (fileio_is_volume_exist (active_log_path) == false)
1584  {
1585  return ER_FAILED;
1586  }
1587 
1588  int log_vdes = fileio_open (active_log_path, O_RDONLY, 0);
1589  if (log_vdes == NULL_VOLDES)
1590  {
1591  return ER_FAILED;
1592  }
1593 
1594  phy_pageid = LOGPB_PHYSICAL_HEADER_PAGE_ID;
1595  logpb_log ("reading from active log:%s, physical page is : %lld\n", active_log_path, (long long int) phy_pageid);
1596 
1597  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
1598 
1599  if (fileio_read (thread_p, log_vdes, log_pgptr, phy_pageid, LOG_PAGESIZE) == NULL)
1600  {
1601  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_READ, 3, LOGPB_HEADER_PAGE_ID, phy_pageid, active_log_path);
1602  error_code = ER_LOG_READ;
1603  goto end;
1604  }
1605 
1606  log_hdr = (LOG_HEADER *) (log_pgptr->area);
1607  *hdr = *log_hdr;
1608 
1609  if (log_pgptr->hdr.logical_pageid != LOGPB_HEADER_PAGE_ID || log_pgptr->hdr.offset != NULL_OFFSET)
1610  {
1612  error_code = ER_LOG_PAGE_CORRUPTED;
1613  goto end;
1614  }
1615 
1616 end:
1617  fileio_close (log_vdes);
1618 
1619  return error_code;
1620 }
1621 
1622 // it probes whether the next archive file exists
1623 // if the case, the backuped log active file is regarded as unuseful and restore will reset log.
1624 static bool
1625 logpb_is_log_active_from_backup_useful (THREAD_ENTRY * thread_p, const char *active_log_path, const char *db_full_name)
1626 {
1627  LOG_HEADER hdr;
1628 
1629  if (logpb_peek_header_of_active_log_from_backup (thread_p, active_log_path, &hdr) != NO_ERROR)
1630  {
1631  // something bad happened
1632  return false;
1633  }
1634 
1635  // make next archive name
1636  char next_archive_file_path[PATH_MAX], log_path[PATH_MAX];
1637 
1638  fileio_get_directory_path (log_path, active_log_path);
1639  fileio_make_log_archive_name (next_archive_file_path, log_path, fileio_get_base_file_name (db_full_name),
1640  hdr.nxarv_num);
1641 
1642  if (fileio_is_volume_exist (next_archive_file_path))
1643  {
1644  // if the next archive exists, regard the backuped log active is older and useless.
1645  er_log_debug (ARG_FILE_LINE, "log active from backup is older than available archive (%s).\n",
1646  next_archive_file_path);
1647  return false;
1648  }
1649 
1650  return true;
1651 }
1652 
1653 /*
1654  * logpb_flush_header - Flush log header
1655  *
1656  * return: nothing
1657  *
1658  * NOTE:Flush out the log header from the global variable log_Gl.hdr to disk. Note append pages are not flushed.
1659  */
1660 void
1662 {
1663  LOG_HEADER *log_hdr;
1664 #if defined(CUBRID_DEBUG)
1665  struct timeval start_time = { 0, 0 };
1666  struct timeval end_time = { 0, 0 };
1667 
1668  css_gettimeofday (&start_time, NULL);
1669 #endif /* CUBRID_DEBUG */
1670 
1671  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
1672 
1673  if (log_Gl.loghdr_pgptr == NULL)
1674  {
1676 
1677  /* This is just a safe guard. log_initialize frees log_Gl.loghdr_pgptr when it fails. It can only happen when
1678  * deletedb or emergency utilities fail to initialize log. */
1679  log_Gl.loghdr_pgptr = (LOG_PAGE *) malloc (LOG_PAGESIZE);
1680  if (log_Gl.loghdr_pgptr == NULL)
1681  {
1683  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "logpb_flush_header");
1684  return;
1685  }
1687  }
1688 
1689  log_hdr = (LOG_HEADER *) (log_Gl.loghdr_pgptr->area);
1690  *log_hdr = log_Gl.hdr;
1691 
1694  log_Gl.loghdr_pgptr->hdr.flags = 0; /* Now flags in header page has always 0 value */
1695 
1697 
1698  log_Stat.flush_hdr_call_count++;
1699 #if defined(CUBRID_DEBUG)
1700  gettimeofday (&end_time, NULL);
1701  log_Stat.last_flush_hdr_sec_by_LFT = LOG_GET_ELAPSED_TIME (end_time, start_time);
1703 #endif /* CUBRID_DEBUG */
1704 
1705 #if defined(CUBRID_DEBUG)
1706  er_log_debug (ARG_FILE_LINE, "log_flush_hdr: call count(%ld) avg flush (%f) \n", log_Stat.flush_hdr_call_count,
1707  (double) log_Stat.total_flush_hdr_sec_by_LFT / log_Stat.flush_hdr_call_count);
1708 #endif /* CUBRID_DEBUG */
1709 }
1710 
1711 /*
1712  * logpb_fetch_page - Fetch a exist_log page using local buffer
1713  *
1714  * return: NO_ERROR if everything is ok, else ER_FAILED
1715  *
1716  * pageid(in): Page identifier
1717  * log_pgptr(in/out): Page buffer to copy
1718  *
1719  * NOTE:Fetch the log page identified by pageid into a log buffer and return such buffer.
1720  * If there is the page in the log page buffer, copy it to buffer and return it.
1721  * If not, read log page from log.
1722  */
1723 int
1724 logpb_fetch_page (THREAD_ENTRY * thread_p, const LOG_LSA * req_lsa, LOG_CS_ACCESS_MODE access_mode,
1725  LOG_PAGE * log_pgptr)
1726 {
1727  LOG_LSA append_lsa, append_prev_lsa;
1728  int rv;
1729 
1730  assert (log_pgptr != NULL);
1731  assert (req_lsa != NULL);
1732  assert (req_lsa->pageid != NULL_PAGEID);
1733 
1734  logpb_log ("called logpb_fetch_page with pageid = %lld\n", (long long int) req_lsa->pageid);
1735 
1736  LSA_COPY (&append_lsa, &log_Gl.hdr.append_lsa);
1737  LSA_COPY (&append_prev_lsa, &log_Gl.append.prev_lsa);
1738 
1739  /*
1740  * This If block ensure belows,
1741  * case 1. log page (of pageid) is in log page buffer (not prior_lsa list)
1742  * case 2. EOL record which is written temporarily by
1743  * logpb_flush_all_append_pages is cleared so there is no EOL
1744  * in log page
1745  */
1746 
1747  if (LSA_LE (&append_lsa, req_lsa) /* for case 1 */
1748  || LSA_LE (&append_prev_lsa, req_lsa)) /* for case 2 */
1749  {
1750  LOG_CS_ENTER (thread_p);
1751 
1753 
1754  /*
1755  * copy prior lsa list to log page buffer to ensure that required
1756  * pageid is in log page buffer
1757  */
1758  if (LSA_LE (&log_Gl.hdr.append_lsa, req_lsa)) /* retry with mutex */
1759  {
1761  }
1762 
1763  LOG_CS_EXIT (thread_p);
1764  }
1765 
1766  /*
1767  * most of the cases, we don't need calling logpb_copy_page with LOG_CS exclusive access,
1768  * if needed, we acquire READ mode in logpb_copy_page
1769  */
1770  rv = logpb_copy_page (thread_p, req_lsa->pageid, access_mode, log_pgptr);
1771  if (rv != NO_ERROR)
1772  {
1773  ASSERT_ERROR ();
1774  return ER_FAILED;
1775  }
1776 
1777  return NO_ERROR;
1778 }
1779 
1780 /*
1781  * logpb_copy_page_from_log_buffer -
1782  *
1783  * return: NO_ERROR if everything is ok
1784  * pageid(in): Page identifier
1785  * log_pgptr(in/out): Page buffer
1786  */
1787 int
1789 {
1790  int rv;
1791 
1792  assert (log_pgptr != NULL);
1793  assert (pageid != NULL_PAGEID);
1794  assert (pageid <= log_Gl.hdr.append_lsa.pageid);
1795 
1796  logpb_log ("called logpb_copy_page_from_log_buffer with pageid = %lld\n", (long long int) pageid);
1797 
1798  rv = logpb_copy_page (thread_p, pageid, LOG_CS_FORCE_USE, log_pgptr);
1799  if (rv != NO_ERROR)
1800  {
1801  ASSERT_ERROR ();
1802  return ER_FAILED;
1803  }
1804 
1805  return NO_ERROR;
1806 }
1807 
1808 /*
1809  * logpb_copy_page_from_file -
1810  * pageid(in): Page identifier
1811  * log_pgptr(in/out): Page buffer
1812  * return: NO_ERROR if everything is ok
1813  *
1814  */
1815 int
1817 {
1818  int rv;
1819 
1820  assert (log_pgptr != NULL);
1821  assert (pageid != NULL_PAGEID);
1822  assert (pageid <= log_Gl.hdr.append_lsa.pageid);
1823 
1824  logpb_log ("called logpb_copy_page_from_file with pageid = %lld\n", (long long int) pageid);
1825 
1826  LOG_CS_ENTER_READ_MODE (thread_p);
1827  if (log_pgptr != NULL)
1828  {
1829  rv = logpb_read_page_from_file (thread_p, pageid, LOG_CS_FORCE_USE, log_pgptr);
1830  if (rv != NO_ERROR)
1831  {
1832  LOG_CS_EXIT (thread_p);
1833  return ER_FAILED;
1834  }
1835  }
1836  LOG_CS_EXIT (thread_p);
1837 
1838  return NO_ERROR;
1839 }
1840 
1841 /*
1842  * logpb_copy_page - copy a exist_log page using local buffer
1843  *
1844  * return: NO_ERROR if everything is ok
1845  *
1846  * pageid(in): Page identifier
1847  * access_mode(in): access mode (reader, safe reader, writer)
1848  * log_pgptr(in/out): Page buffer to copy
1849  *
1850  * NOTE:Fetch the log page identified by pageid into a log buffer and return such buffer.
1851  * If there is the page in the log page buffer, copy it to buffer and return it.
1852  * If not, read log page from log.
1853  */
1854 
1855 static int
1857 {
1858  LOG_BUFFER *log_bufptr = NULL;
1859  bool is_perf_tracking;
1860  TSC_TICKS start_tick, end_tick;
1861  TSCTIMEVAL tv_diff;
1862  UINT64 fix_wait_time;
1863  PERF_PAGE_MODE stat_page_found = PERF_PAGE_MODE_OLD_IN_BUFFER;
1864  bool log_csect_entered = false;
1865  int rv = NO_ERROR, index;
1866 
1867  assert (log_pgptr != NULL);
1868  assert (pageid != NULL_PAGEID);
1869 
1870  logpb_log ("called logpb_copy_page with pageid = %lld\n", (long long int) pageid);
1871 
1872  is_perf_tracking = perfmon_is_perf_tracking ();
1873  if (is_perf_tracking)
1874  {
1875  tsc_getticks (&start_tick);
1876  }
1877 
1878  if (access_mode != LOG_CS_SAFE_READER)
1879  {
1880  LOG_CS_ENTER_READ_MODE (thread_p);
1881  log_csect_entered = true;
1882  }
1883 
1884  if (pageid == LOGPB_HEADER_PAGE_ID)
1885  {
1886  /* copy header page into log_pgptr */
1887  log_bufptr = &log_Pb.header_buffer;
1888 
1889  if (log_bufptr->pageid == NULL_PAGEID)
1890  {
1891  rv = logpb_read_page_from_file (thread_p, pageid, access_mode, log_pgptr);
1892  if (rv != NO_ERROR)
1893  {
1894  rv = ER_FAILED;
1895  goto exit;
1896  }
1897  stat_page_found = PERF_PAGE_MODE_OLD_LOCK_WAIT;
1898  }
1899  else
1900  {
1901  memcpy (log_pgptr, log_bufptr->logpage, LOG_PAGESIZE);
1902  }
1903 
1904  goto exit;
1905  }
1906 
1907  index = logpb_get_log_buffer_index ((int) pageid);
1908  if (index >= 0 && index < log_Pb.num_buffers)
1909  {
1910  log_bufptr = &log_Pb.buffers[index];
1911  }
1912  else
1913  {
1915  return ER_LOG_PAGE_CORRUPTED;
1916  }
1917 
1918  if (log_bufptr->pageid == pageid)
1919  {
1920  /* Copy page from log_bufptr into log_pgptr */
1921  memcpy (log_pgptr, log_bufptr->logpage, LOG_PAGESIZE);
1922  if (log_bufptr->pageid == pageid)
1923  {
1924  goto exit;
1925  }
1926  }
1927 
1928  /* Could not get from log page buffer cache */
1929  rv = logpb_read_page_from_file (thread_p, pageid, access_mode, log_pgptr);
1930  if (rv != NO_ERROR)
1931  {
1932  rv = ER_FAILED;
1933  goto exit;
1934  }
1935  stat_page_found = PERF_PAGE_MODE_OLD_LOCK_WAIT;
1936 
1937  /* Always exit through here */
1938 exit:
1939  if (log_csect_entered)
1940  {
1941  LOG_CS_EXIT (thread_p);
1942  }
1944 
1945  if (is_perf_tracking)
1946  {
1947  tsc_getticks (&end_tick);
1948  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
1949  fix_wait_time = tv_diff.tv_sec * 1000000LL + tv_diff.tv_usec;
1950  /* log page fix time : use dummy values for latch type and conditional type; use PERF_PAGE_MODE_OLD_LOCK_WAIT and
1951  * PERF_PAGE_MODE_OLD_IN_BUFFER for page type : page is not found in log page buffer and must be read from
1952  * archive vs page is found in log page buffer */
1953  if (fix_wait_time > 0)
1954  {
1955  perfmon_pbx_fix_acquire_time (thread_p, PAGE_LOG, stat_page_found, PERF_HOLDER_LATCH_READ,
1956  PERF_UNCONDITIONAL_FIX_WITH_WAIT, fix_wait_time);
1957  }
1958  }
1959 
1960  return rv;
1961 }
1962 
1963 /*
1964  * logpb_read_page_from_file - Fetch a exist_log page from log files
1965  *
1966  * return: NO_ERROR if everything is ok, else ER_GENERIC_ERROR
1967  *
1968  * pageid(in): Page identifier
1969  * log_pgptr(in/out): Page buffer to read
1970  *
1971  * NOTE:read the log page identified by pageid into a buffer from from archive or active log.
1972  */
1973 int
1975  LOG_PAGE * log_pgptr)
1976 {
1977  bool log_csect_entered = false;
1978 
1979  assert (log_pgptr != NULL);
1980  assert (pageid != NULL_PAGEID);
1981 
1982  logpb_log ("called logpb_read_page_from_file with pageid = %lld, hdr.logical_pageid = %lld, "
1983  "LOGPB_ACTIVE_NPAGES = %d\n", (long long int) pageid, (long long int) log_pgptr->hdr.logical_pageid,
1985 
1986  if (access_mode == LOG_CS_SAFE_READER)
1987  {
1988  /* This is added here to block others from creating new archive or mounting/dismounting archives while the vacuum
1989  * workers is trying to fetch its page from file. */
1990  /* This was first done only for active pages. This allowed other transaction create a new archive from active log
1991  * after calling logpb_is_page_in_archive. Therefore the logpb_to_physical_pageid became flawed. */
1992  LOG_CS_ENTER_READ_MODE (thread_p);
1993  log_csect_entered = true;
1994  }
1995  else
1996  {
1997  assert (LOG_CS_OWN (thread_p));
1998  }
1999 
2000  // some archived pages may be still in active log; check if they can be fetched from active.
2001  bool fetch_from_archive = logpb_is_page_in_archive (pageid);
2002  if (fetch_from_archive)
2003  {
2004  bool is_archive_page_in_active_log = (pageid + LOGPB_ACTIVE_NPAGES) > log_Gl.hdr.append_lsa.pageid;
2005  bool dont_fetch_archive_from_active = !LOG_ISRESTARTED () || log_Gl.hdr.was_active_log_reset;
2006 
2007  if (is_archive_page_in_active_log && !dont_fetch_archive_from_active)
2008  {
2009  // can fetch from active
2010  fetch_from_archive = false;
2011  }
2012  }
2013  if (fetch_from_archive)
2014  {
2015  // fetch from archive
2016  if (logpb_fetch_from_archive (thread_p, pageid, log_pgptr, NULL, NULL, true) == NULL)
2017  {
2018 #if defined (SERVER_MODE)
2019  if (thread_p != NULL && thread_p->type == TT_VACUUM_MASTER)
2020  {
2022  "Failed to fetch page %lld from archives.", pageid);
2023  }
2024 #endif /* SERVER_MODE */
2025  goto error;
2026  }
2027  }
2028  else
2029  {
2030  // fetch from active
2032 
2033  /*
2034  * Page is contained in the active log.
2035  * Find the corresponding physical page and read the page form disk.
2036  */
2037  phy_pageid = logpb_to_physical_pageid (pageid);
2038  logpb_log ("phy_pageid in logpb_read_page_from_file is %lld\n", (long long int) phy_pageid);
2039 
2041 
2042  if (fileio_read (thread_p, log_Gl.append.vdes, log_pgptr, phy_pageid, LOG_PAGESIZE) == NULL)
2043  {
2045  goto error;
2046  }
2047  else
2048  {
2049  if (log_pgptr->hdr.logical_pageid != pageid)
2050  {
2051  if (log_pgptr->hdr.logical_pageid == pageid + LOGPB_ACTIVE_NPAGES)
2052  {
2053  /* The active part where this archive page belonged was already, overwritten. Fetch the page from
2054  * archive. */
2055  if (logpb_fetch_from_archive (thread_p, pageid, log_pgptr, NULL, NULL, true) == NULL)
2056  {
2057 #if defined (SERVER_MODE)
2058  if (thread_p != NULL && thread_p->type == TT_VACUUM_MASTER)
2059  {
2061  "Failed to fetch page %lld from archives.", pageid);
2062  }
2063 #endif /* SERVER_MODE */
2064  goto error;
2065  }
2066  }
2067  else
2068  {
2069  /* Clean the buffer... since it may be corrupted */
2071  goto error;
2072  }
2073  }
2074  else
2075  {
2076  /*
2077  * fetched from active.
2078  * In case of being fetched from archive log, no need to be decrypted
2079  * because it already decrypted in logpb_fetch_from_archive()
2080  */
2081  TDE_ALGORITHM tde_algo = logpb_get_tde_algorithm ((LOG_PAGE *) log_pgptr);
2082  if (tde_algo != TDE_ALGORITHM_NONE)
2083  {
2084  if (tde_decrypt_log_page ((LOG_PAGE *) log_pgptr, tde_algo, (LOG_PAGE *) log_pgptr) != NO_ERROR)
2085  {
2086  ASSERT_ERROR ();
2087  goto error;
2088  }
2089  }
2090  }
2091  }
2092  }
2093 
2094  if (log_csect_entered)
2095  {
2096  LOG_CS_EXIT (thread_p);
2097  }
2098 
2099  logpb_log ("logpb_read_page_from_file: log page %lld has checksum = %d\n",
2100  (long long int) log_pgptr->hdr.logical_pageid, log_pgptr->hdr.checksum);
2101 
2102 #if !defined(NDEBUG)
2104  {
2105  logpb_debug_check_log_page (thread_p, log_pgptr);
2106  }
2107 #endif
2108 
2109  /* keep old function's usage */
2110  return NO_ERROR;
2111 
2112 error:
2113  if (log_csect_entered)
2114  {
2115  LOG_CS_EXIT (thread_p);
2116  }
2117  return ER_FAILED;
2118 }
2119 
2120 /*
2121  * logpb_read_page_from_active_log -
2122  *
2123  * return: new num_pages
2124  *
2125  * pageid(in):
2126  * num_pages(in):
2127  * log_pgptr(in/out):
2128  */
2129 int
2130 logpb_read_page_from_active_log (THREAD_ENTRY * thread_p, LOG_PAGEID pageid, int num_pages, bool decrypt_needed,
2131  LOG_PAGE * log_pgptr)
2132 {
2133  LOG_PHY_PAGEID phy_start_pageid;
2134 
2135  assert (log_pgptr != NULL);
2136  assert (pageid != NULL_PAGEID);
2137  assert (num_pages > 0);
2138 
2139  logpb_log ("called logpb_read_page_from_active_log with pageid = %lld and num_pages = %d\n", (long long int) pageid,
2140  num_pages);
2141 
2142  /*
2143  * Page is contained in the active log.
2144  * Find the corresponding physical page and read the page from disk.
2145  */
2146  phy_start_pageid = logpb_to_physical_pageid (pageid);
2147  num_pages = MIN (num_pages, LOGPB_ACTIVE_NPAGES - phy_start_pageid + 1);
2148 
2150 
2151  if (fileio_read_pages (thread_p, log_Gl.append.vdes, (char *) log_pgptr, phy_start_pageid, num_pages, LOG_PAGESIZE) ==
2152  NULL)
2153  {
2154  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_READ, 3, pageid, phy_start_pageid, log_Name_active);
2155  return -1;
2156  }
2157  else
2158  {
2159  if (log_pgptr->hdr.logical_pageid != pageid)
2160  {
2162  return -1;
2163  }
2164  }
2165 
2166  if (decrypt_needed)
2167  {
2168  char *ptr = (char *) log_pgptr;
2169  int i;
2170  for (i = 0; i < num_pages; i++)
2171  {
2172  TDE_ALGORITHM tde_algo = logpb_get_tde_algorithm ((LOG_PAGE *) ptr);
2173  if (tde_algo != TDE_ALGORITHM_NONE)
2174  {
2175  if (tde_decrypt_log_page ((LOG_PAGE *) ptr, tde_algo, (LOG_PAGE *) ptr) != NO_ERROR)
2176  {
2177  ASSERT_ERROR ();
2178  return -1;
2179  }
2180  }
2181  ptr += LOG_PAGESIZE;
2182  }
2183  }
2184 
2185 #if !defined(NDEBUG)
2187  {
2188  char *ptr = NULL;
2189  int i;
2190  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
2191  char *aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
2192 
2193  ptr = (char *) log_pgptr;
2194  for (i = 0; i < num_pages; i++)
2195  {
2196  TDE_ALGORITHM tde_algo = logpb_get_tde_algorithm ((LOG_PAGE *) ptr);
2197  /* checksum is calculated before tde-encryption */
2198  if (!decrypt_needed && tde_algo != TDE_ALGORITHM_NONE)
2199  {
2200  /* This page is tde-ecnrypted page and has not yet decrypted.
2201  * To check consistency, we need to decrypt it */
2202  if (!tde_Cipher.is_loaded)
2203  {
2204  ptr += LOG_PAGESIZE;
2205  continue; /* no way to check an encrypted page without tde module */
2206  }
2207 
2208  if (tde_decrypt_log_page ((LOG_PAGE *) ptr, tde_algo, (LOG_PAGE *) aligned_log_pgbuf) != NO_ERROR)
2209  {
2210  ASSERT_ERROR ();
2211  assert (false);
2212  }
2213  logpb_debug_check_log_page (thread_p, (LOG_PAGE *) aligned_log_pgbuf);
2214  ptr += LOG_PAGESIZE;
2215  }
2216  else
2217  {
2218  logpb_debug_check_log_page (thread_p, (LOG_PAGE *) ptr);
2219  ptr += LOG_PAGESIZE;
2220  }
2221  }
2222  }
2223 #endif
2224 
2225  return num_pages;
2226 }
2227 
2228 /*
2229  * logpb_write_page_to_disk - writes and syncs a log page to disk
2230  *
2231  * return: error code
2232  *
2233  * log_pgptr(in/out): Log page pointer
2234  * logical_pageid(in): logical page id
2235  *
2236  * NOTE:writes and syncs a log page to disk
2237  */
2238 int
2239 logpb_write_page_to_disk (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, LOG_PAGEID logical_pageid)
2240 {
2241  int nbytes, error_code;
2243  FILEIO_WRITE_MODE write_mode;
2244  char enc_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
2245  LOG_PAGE *enc_pgptr = NULL;
2246 
2247  enc_pgptr = (LOG_PAGE *) PTR_ALIGN (enc_pgbuf, MAX_ALIGNMENT);
2248 
2249  assert (log_pgptr != NULL);
2250  assert (log_pgptr->hdr.logical_pageid == logical_pageid);
2251  /* we allow writing page as long as they do not belong to archive area */
2252  assert (logical_pageid == LOGPB_HEADER_PAGE_ID
2253  || (!LOGPB_IS_ARCHIVE_PAGE (logical_pageid) && logical_pageid <= LOGPB_LAST_ACTIVE_PAGE_ID));
2254 
2255  logpb_log ("called logpb_write_page_to_disk for logical_pageid = %lld\n", (long long int) logical_pageid);
2256 
2257  /* Set page CRC before writing to disk. */
2258  error_code = logpb_set_page_checksum (thread_p, log_pgptr);
2259  if (error_code != NO_ERROR)
2260  {
2261  return error_code;
2262  }
2263 
2264  phy_pageid = logpb_to_physical_pageid (logical_pageid);
2265  logpb_log ("phy_pageid in logpb_write_page_to_disk is %lld\n", (long long int) phy_pageid);
2266 
2267  /* log_Gl.append.vdes is only changed while starting or finishing or recovering server. So, log cs is not needed. */
2268 
2270 
2271  logpb_log ("logpb_write_page_to_disk: The page (%lld) is being tde-encrypted: %d\n", (long long int) logical_pageid,
2272  LOG_IS_PAGE_TDE_ENCRYPTED (log_pgptr));
2273 
2274  if (LOG_IS_PAGE_TDE_ENCRYPTED (log_pgptr))
2275  {
2276  error_code = tde_encrypt_log_page (log_pgptr, logpb_get_tde_algorithm (log_pgptr), enc_pgptr);
2277  if (error_code != NO_ERROR)
2278  {
2279  /*
2280  * if encrpytion fails, it just skip it and off the tde flag. The page will never be encrypted in this case.
2281  * It menas once it fails, the page always spill user data un-encrypted from then.
2282  */
2283  logpb_set_tde_algorithm (thread_p, log_pgptr, TDE_ALGORITHM_NONE);
2285  }
2286  else
2287  {
2288  log_pgptr = enc_pgptr;
2289  }
2290  }
2291 
2292  if (fileio_write (thread_p, log_Gl.append.vdes, log_pgptr, phy_pageid, LOG_PAGESIZE, write_mode) == NULL)
2293  {
2295  {
2296  nbytes = log_Gl.hdr.db_logpagesize;
2297  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_WRITE_OUT_OF_SPACE, 4, logical_pageid, phy_pageid,
2298  log_Name_active, nbytes);
2299  }
2300  else
2301  {
2302  er_set_with_oserror (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_WRITE, 3, logical_pageid, phy_pageid,
2303  log_Name_active);
2304  }
2305 
2306  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "logpb_write_page_to_disk");
2307  return ER_FAILED;
2308  }
2309 
2311  return NO_ERROR;
2312 }
2313 
2314 /*
2315  * logpb_find_header_parameters - Find some database creation parameters
2316  *
2317  * return: iopagesize or -1
2318  *
2319  * db_fullname(in): Full name of the database
2320  * force_read_log_header(in): force to read log header
2321  * logpath(in): Directory where the log volumes reside
2322  * prefix_logname(in): Name of the log volumes. It is usually set as database
2323  * name. For example, if the value is equal to "db", the
2324  * names of the log volumes created are as follow:
2325  * Active_log = db_logactive
2326  * Archive_logs = db_logarchive.0
2327  * db_logarchive.1
2328  * .
2329  * .
2330  * .
2331  * db_logarchive.n
2332  * Log_information = db_loginfo
2333  * Database Backup = db_backup
2334  * db_iopagesize(in): Set as a side effect to iopagesize
2335  * db_creation(in): Set as a side effect to time of database creation
2336  * db_compatibility(in): Set as a side effect to database disk compatibility
2337  * db_charset(in): Set as a side effect to database charset
2338  *
2339  * NOTE:Find some database creation parameters such as pagesize, creation time, and disk compatability.
2340  */
2341 PGLENGTH
2342 logpb_find_header_parameters (THREAD_ENTRY * thread_p, const bool force_read_log_header, const char *db_fullname,
2343  const char *logpath, const char *prefix_logname, PGLENGTH * io_page_size,
2344  PGLENGTH * log_page_size, INT64 * creation_time, float *db_compatibility, int *db_charset)
2345 {
2346  static LOG_HEADER hdr; /* Log header */
2347  static bool is_header_read_from_file = false;
2348  static bool is_log_header_validated = false;
2349  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
2350  LOG_PAGE *log_pgptr = NULL;
2351  int error_code = NO_ERROR;
2352 
2353  if (force_read_log_header)
2354  {
2355  is_header_read_from_file = false;
2356  is_log_header_validated = false;
2357  }
2358 
2359  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
2360 
2361  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
2362 
2363  /* Is the system restarted ? */
2365  {
2366  *io_page_size = log_Gl.hdr.db_iopagesize;
2367  *log_page_size = log_Gl.hdr.db_logpagesize;
2368  *creation_time = log_Gl.hdr.db_creation;
2369  *db_compatibility = log_Gl.hdr.db_compatibility;
2370 
2371  if (IO_PAGESIZE != *io_page_size || LOG_PAGESIZE != *log_page_size)
2372  {
2373  if (db_set_page_size (*io_page_size, *log_page_size) != NO_ERROR)
2374  {
2375  goto error;
2376  }
2377 
2378  logpb_finalize_pool (thread_p);
2380  if (error_code != NO_ERROR)
2381  {
2382  goto error;
2383  }
2384  error_code = logpb_initialize_pool (thread_p);
2385  if (error_code != NO_ERROR)
2386  {
2387  goto error;
2388  }
2389  if (logpb_fetch_start_append_page (thread_p) != NO_ERROR)
2390  {
2391  goto error;
2392  }
2393  }
2394  return *io_page_size;
2395  }
2396 
2397  if (!is_header_read_from_file)
2398  {
2399  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
2400 
2401  error_code = logpb_fetch_header_from_active_log (thread_p, db_fullname, logpath, prefix_logname, &hdr, log_pgptr);
2402  if (error_code != NO_ERROR)
2403  {
2404  goto error;
2405  }
2406  is_header_read_from_file = true;
2407  }
2408 
2409  *io_page_size = hdr.db_iopagesize;
2410  *log_page_size = hdr.db_logpagesize;
2411  *creation_time = hdr.db_creation;
2412  *db_compatibility = hdr.db_compatibility;
2413  *db_charset = (int) hdr.db_charset;
2414 
2415  if (is_log_header_validated)
2416  {
2417  return *io_page_size;
2418  }
2419 
2420  /*
2421  * Make sure that the log is a log file and that it is compatible with the
2422  * running database and system
2423  */
2424 
2425  if (strcmp (hdr.prefix_name, prefix_logname) != 0)
2426  {
2427  /*
2428  * This does not look like the log or the log was renamed. Incompatible
2429  * prefix name with the prefix stored on disk
2430  */
2432  hdr.prefix_name);
2433  /* Continue anyhow.. */
2434  }
2435 
2436  /* only check for incompatibility here, this will be done again in log_xinit which will run the compatibility
2437  * functions if there are any. */
2438  /* We added disk compatibility rules to R2.2. Before that release, rel_get_disk_compatible function returned only
2439  * REL_FULLY_COMPATIBLE or REL_NOT_COMPATIBLE. However, it might return REL_BACKWARD_COMPATIBLE now. */
2440  if (rel_get_disk_compatible (*db_compatibility, NULL) != REL_FULLY_COMPATIBLE)
2441  {
2442  log_Gl.hdr.db_compatibility = *db_compatibility;
2444  error_code = ER_LOG_INCOMPATIBLE_DATABASE;
2445  goto error;
2446  }
2447 
2448  is_log_header_validated = true;
2449 
2450  return *io_page_size;
2451 
2452 error:
2453  *io_page_size = -1;
2454  *log_page_size = -1;
2455  *creation_time = 0;
2456  *db_compatibility = -1.0;
2457 
2458  return *io_page_size;
2459 }
2460 
2461 /*
2462  *
2463  * FUNCTIONS RELATED TO APPEND PAGES
2464  *
2465  */
2466 
2467 /*
2468  * logpb_fetch_start_append_page - FETCH THE START APPEND PAGE
2469  *
2470  * return: Pointer to the page or NULL
2471  *
2472  * NOTE:Fetch the start append page.
2473  */
2474 int
2476 {
2477  LOG_FLUSH_INFO *flush_info = &log_Gl.flush_info;
2479  bool need_flush;
2480 #if defined(SERVER_MODE)
2481  int rv;
2482 #endif /* SERVER_MODE */
2483 
2484  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
2485 
2486  logpb_log ("started logpb_fetch_start_append_page\n");
2487 
2488  /* detect empty log (page and offset of zero) */
2489  if ((log_Gl.hdr.append_lsa.pageid == 0) && (log_Gl.hdr.append_lsa.offset == 0))
2490  {
2491  flag = NEW_PAGE;
2492  }
2493 
2494  if (log_Gl.append.log_pgptr != NULL)
2495  {
2496  /*
2497  * Somehow we already have an append page, flush all current append page
2498  * and start form scratch
2499  */
2500  logpb_invalid_all_append_pages (thread_p);
2501  }
2502 
2503  /*
2504  * Fetch the start append page
2505  */
2506 
2508  if (log_Gl.append.log_pgptr == NULL)
2509  {
2510  return ER_FAILED;
2511  }
2512 
2514  /*
2515  * Save this log append page as an active page to be flushed at a later
2516  * time if the page is modified (dirty).
2517  * We must save the log append pages in the order that they are defined
2518  * and need to be flushed.
2519  */
2520 
2521  need_flush = false;
2522 
2523  rv = pthread_mutex_lock (&flush_info->flush_mutex);
2524 
2525  flush_info->toflush[flush_info->num_toflush] = log_Gl.append.log_pgptr;
2526  flush_info->num_toflush++;
2527 
2528  if (flush_info->num_toflush >= flush_info->max_toflush)
2529  {
2530  /*
2531  * Force the dirty pages including the current one at this moment
2532  */
2533  need_flush = true;
2534  }
2535 
2536  pthread_mutex_unlock (&flush_info->flush_mutex);
2537 
2538  if (need_flush)
2539  {
2540  logpb_flush_pages_direct (thread_p);
2541  }
2542 
2543  return NO_ERROR;
2544 }
2545 
2546 /*
2547  * logpb_fetch_start_append_page_new - FETCH THE NEW START APPEND PAGE
2548  *
2549  * return: Pointer to the page or NULL
2550  */
2551 LOG_PAGE *
2553 {
2554  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
2555 
2556  logpb_log ("started logpb_fetch_start_append_page_new\n");
2557 
2559  if (log_Gl.append.log_pgptr == NULL)
2560  {
2561  return NULL;
2562  }
2563 
2565 
2566  return log_Gl.append.log_pgptr;
2567 }
2568 
2569 /*
2570  * logpb_next_append_page - Fetch next append page
2571  *
2572  * return: nothing
2573  *
2574  * current_setdirty(in): Set the current append page dirty ?
2575  *
2576  * NOTE:Fetch the next append page.
2577  * If the current append page contains the beginning of the log
2578  * record being appended (i.e., log record did fit on current
2579  * append page), the freeing of this page is delayed until the
2580  * record is completely appended/logged. This is needed since
2581  * every log record has a forward pointer to next log record
2582  * (i.e., next append address). In addition, we must avoid
2583  * flushing this page to disk (e.g., page replacement),
2584  * otherwise, during crash recovery we could try to read a log
2585  * record that has never been finished and the end of the log may
2586  * not be detected. That is, the log would be corrupted.
2587  *
2588  * If the current append page does not contain the beginning of
2589  * the log record, the page can be freed and flushed at any time.
2590  *
2591  * If the next page to archive is located at the physical
2592  * location of the desired append page, a set of log pages is
2593  * archived, so we can continue the append operations.
2594  */
2595 static void
2596 logpb_next_append_page (THREAD_ENTRY * thread_p, LOG_SETDIRTY current_setdirty)
2597 {
2598  LOG_FLUSH_INFO *flush_info = &log_Gl.flush_info;
2599  bool need_flush;
2600 #if defined(SERVER_MODE)
2601  int rv;
2602 #endif /* SERVER_MODE */
2603 #if defined(CUBRID_DEBUG)
2604  long commit_count = 0;
2605  static struct timeval start_append_time = { 0, 0 };
2606  struct timeval end_append_time = { 0, 0 };
2607  static long prev_commit_count_in_append = 0;
2608  double elapsed = 0;
2609 
2610  gettimeofday (&end_append_time, NULL);
2611 #endif /* CUBRID_DEBUG */
2612 
2613  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
2614 
2615  logpb_log ("started logpb_next_append_page\n");
2616 
2617  if (current_setdirty == LOG_SET_DIRTY)
2618  {
2619  logpb_set_dirty (thread_p, log_Gl.append.log_pgptr);
2620  }
2621 
2623 
2626 
2627  /*
2628  * Is the next logical page to archive, currently located at the physical
2629  * location of the next logical append page ? (Remember the log is a RING).
2630  * If so, we need to archive the log from the next logical page to archive
2631  * up to the closest page that does not hold the current append log record.
2632  */
2633 
2635  {
2636  /* The log must be archived */
2637  logpb_archive_active_log (thread_p);
2638  }
2639 
2640  /*
2641  * Has the log been cycled ?
2642  */
2644  {
2646 
2647  /* Flush the header to save updates by archiving. */
2648  logpb_flush_header (thread_p);
2649  }
2650 
2651  /*
2652  * Fetch the next page as a newly defined append page. Append pages are
2653  * always new pages
2654  */
2655 
2657  if (log_Gl.append.log_pgptr == NULL)
2658  {
2659  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_next_append_page");
2660  /* This statement should not be reached */
2661  return;
2662  }
2663 
2665  {
2667  logpb_set_tde_algorithm (thread_p, log_Gl.append.log_pgptr, tde_algo);
2668  logpb_set_dirty (thread_p, log_Gl.append.log_pgptr);
2669  logpb_log ("logpb_next_append_page: set tde_algorithm to appending page (%lld), "
2670  "tde_algorithm = %s\n", (long long int) log_Gl.append.log_pgptr->hdr.logical_pageid,
2671  tde_get_algorithm_name (tde_algo));
2672  }
2673 
2674 #if defined(CUBRID_DEBUG)
2675  {
2677  }
2678 #endif /* CUBRID_DEBUG */
2679 
2680  /*
2681  * Save this log append page as an active page to be flushed at a later
2682  * time if the page is modified (dirty).
2683  * We must save the log append pages in the order that they are defined
2684  * and need to be flushed.
2685  */
2686 
2687  rv = pthread_mutex_lock (&flush_info->flush_mutex);
2688 
2689  flush_info->toflush[flush_info->num_toflush] = log_Gl.append.log_pgptr;
2690  flush_info->num_toflush++;
2691 
2692  need_flush = false;
2693  if (flush_info->num_toflush >= flush_info->max_toflush)
2694  {
2695  need_flush = true;
2696  }
2697 
2698  pthread_mutex_unlock (&flush_info->flush_mutex);
2699 
2700  if (need_flush)
2701  {
2702  logpb_flush_all_append_pages (thread_p);
2703  }
2704 
2705 #if defined(CUBRID_DEBUG)
2706  if (start_append_time.tv_sec != 0 && start_append_time.tv_usec != 0)
2707  {
2708  elapsed = LOG_GET_ELAPSED_TIME (end_append_time, start_append_time);
2709  }
2710 
2711  log_Stat.use_append_page_sec = elapsed;
2712  gettimeofday (&start_append_time, NULL);
2713 
2714  commit_count = log_Stat.commit_count - prev_commit_count_in_append;
2715 
2716  prev_commit_count_in_append = log_Stat.commit_count;
2717 
2718  log_Stat.last_commit_count_while_using_a_page = commit_count;
2720 #endif /* CUBRID_DEBUG */
2721 
2722  log_Stat.total_append_page_count++;
2723 
2724 #if defined(CUBRID_DEBUG)
2726  "log_next_append_page: new page id(%lld) total_append_page_count(%ld)"
2727  " num_toflush(%d) use_append_page_sec(%f) need_flush(%d) commit_count(%ld)"
2728  " total_commit_count(%ld)\n", (int) log_Stat.last_append_pageid, log_Stat.total_append_page_count,
2729  flush_info->num_toflush, log_Stat.use_append_page_sec, need_flush,
2731 #endif /* CUBRID_DEBUG */
2732 }
2733 
2734 /*
2735  * log_writev_append_pages - Write a set of sequential pages
2736  *
2737  * return: to_flush or NULL
2738  *
2739  * to_flush(in): Array to address of content of pages to flush
2740  * npages(in): Number of pages to flush
2741  *
2742  * NOTE:Flush to disk a set of log contiguous pages.
2743  */
2744 static LOG_PAGE **
2745 logpb_writev_append_pages (THREAD_ENTRY * thread_p, LOG_PAGE ** to_flush, DKNPAGES npages)
2746 {
2747  LOG_BUFFER *bufptr;
2749  int i;
2751  char enc_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
2752  LOG_PAGE *log_pgptr = NULL;
2753  LOG_PAGE *enc_pgptr = NULL;
2754 
2755  enc_pgptr = (LOG_PAGE *) PTR_ALIGN (enc_pgbuf, MAX_ALIGNMENT);
2756 
2757 #if !defined (CS_MODE)
2759 #endif
2760 
2761  /* In this point, flush buffer cannot be replaced by trans. So, bufptr's pageid and phy_pageid are not changed. */
2762  if (npages > 0)
2763  {
2764  bufptr = logpb_get_log_buffer (to_flush[0]);
2765  phy_pageid = bufptr->phy_pageid;
2766 
2767  logpb_log ("logpb_writev_append_pages: started with pageid = %lld and phy_pageid = %lld\n",
2768  (long long int) bufptr->pageid, (long long int) phy_pageid);
2769 
2770  for (i = 0; i < npages; i++)
2771  {
2772  /* Set page CRC before writing to disk. */
2773  if (logpb_set_page_checksum (thread_p, to_flush[i]) != NO_ERROR)
2774  {
2775  return NULL;
2776  }
2777  }
2778  for (i = 0; i < npages; i++)
2779  {
2780  log_pgptr = to_flush[i];
2781 
2782  logpb_log ("logpb_writev_append_pages: The page (%lld) is being tde-encrypted: %d\n",
2783  (long long int) log_pgptr->hdr.logical_pageid, LOG_IS_PAGE_TDE_ENCRYPTED (log_pgptr));
2784  if (LOG_IS_PAGE_TDE_ENCRYPTED (log_pgptr))
2785  {
2786  if (tde_encrypt_log_page (log_pgptr, logpb_get_tde_algorithm (log_pgptr), enc_pgptr) != NO_ERROR)
2787  {
2788  /*
2789  * if encrpytion fails, it just skip it and off the tde flag. The page will never be encrypted in this case.
2790  * It menas once it fails, the page always spill user data un-encrypted from then.
2791  */
2792  logpb_set_tde_algorithm (thread_p, log_pgptr, TDE_ALGORITHM_NONE);
2794  log_pgptr->hdr.logical_pageid);
2795  }
2796  else
2797  {
2798  log_pgptr = enc_pgptr;
2799  }
2800  }
2801 
2802  if (fileio_write (thread_p, log_Gl.append.vdes, log_pgptr, phy_pageid + i, LOG_PAGESIZE, write_mode) == NULL)
2803  {
2805  {
2807  phy_pageid, log_Name_active, log_Gl.hdr.db_logpagesize);
2808  }
2809  else
2810  {
2812  phy_pageid, log_Name_active);
2813  }
2814  to_flush = NULL;
2815  break;
2816  }
2817  }
2818  }
2819 
2820  return to_flush;
2821 }
2822 
2823 /*
2824  * logpb_write_toflush_pages_to_archive - Background archiving
2825  *
2826  * NOTE : write flushed pages to temporary archiving volume
2827  * (which will be renamed to real archiving volume) at this time.
2828  * but don't write last page because it will be modified & flushed again.
2829  * in error case, dismount temp archiving volume and give up background
2830  * archiving.
2831  */
2832 static void
2834 {
2835  int i;
2836  LOG_PAGEID pageid, prev_lsa_pageid;
2838  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
2839  char enc_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
2840  LOG_PAGE *log_pgptr = NULL;
2841  LOG_PAGE *enc_pgptr = NULL;
2842  LOG_BUFFER *bufptr;
2843  LOG_FLUSH_INFO *flush_info = &log_Gl.flush_info;
2845  FILEIO_WRITE_MODE write_mode;
2846 
2848 
2849  if (log_Gl.bg_archive_info.vdes == NULL_VOLDES || flush_info->num_toflush <= 1)
2850  {
2851  return;
2852  }
2853 
2854  pageid = bg_arv_info->current_page_id;
2855  prev_lsa_pageid = log_Gl.append.prev_lsa.pageid;
2856  i = 0;
2858 
2859  while (pageid < prev_lsa_pageid && i < flush_info->num_toflush)
2860  {
2861  bufptr = logpb_get_log_buffer (flush_info->toflush[i]);
2862  if (pageid > bufptr->pageid)
2863  {
2864  assert_release (pageid <= bufptr->pageid);
2865  fileio_dismount (thread_p, bg_arv_info->vdes);
2866  bg_arv_info->vdes = NULL_VOLDES;
2867  return;
2868  }
2869  else if (pageid < bufptr->pageid)
2870  {
2871  LOG_LSA current_lsa;
2872 
2873  current_lsa.pageid = pageid;
2874  current_lsa.offset = LOG_PAGESIZE;
2875  /* to flush all omitted pages by the previous archiving */
2876  log_pgptr = (LOG_PAGE *) PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
2877 
2878  if (logpb_fetch_page (thread_p, &current_lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
2879  {
2880  fileio_dismount (thread_p, bg_arv_info->vdes);
2881  bg_arv_info->vdes = NULL_VOLDES;
2882  return;
2883  }
2884  }
2885  else
2886  {
2887  log_pgptr = flush_info->toflush[i];
2888  i++;
2889  }
2890 
2891 #if !defined(NDEBUG)
2892  logpb_debug_check_log_page (thread_p, log_pgptr);
2893 #endif
2894  phy_pageid = (LOG_PHY_PAGEID) (pageid - bg_arv_info->start_page_id + 1);
2895  assert_release (phy_pageid > 0);
2896 
2897  logpb_log ("logpb_write_toflush_pages_to_archive: The page (%lld) is being tde-encrypted: %d\n",
2898  (long long int) pageid, LOG_IS_PAGE_TDE_ENCRYPTED (log_pgptr));
2899 
2900  if (LOG_IS_PAGE_TDE_ENCRYPTED (log_pgptr))
2901  {
2902  enc_pgptr = (LOG_PAGE *) PTR_ALIGN (enc_pgbuf, MAX_ALIGNMENT);
2903  if (tde_encrypt_log_page (log_pgptr, logpb_get_tde_algorithm (log_pgptr), enc_pgptr) != NO_ERROR)
2904  {
2905  /*
2906  * if encrpytion fails, it just skip it and off the tde flag. The page will never be encrypted in this case.
2907  * It menas once it fails, the page always spill user data un-encrypted from then.
2908  */
2909  logpb_set_tde_algorithm (thread_p, log_pgptr, TDE_ALGORITHM_NONE);
2911  }
2912  else
2913  {
2914  log_pgptr = enc_pgptr;
2915  }
2916  }
2917 
2918  if (fileio_write (thread_p, bg_arv_info->vdes, log_pgptr, phy_pageid, LOG_PAGESIZE, write_mode) == NULL)
2919  {
2920  fileio_dismount (thread_p, bg_arv_info->vdes);
2921  bg_arv_info->vdes = NULL_VOLDES;
2922  return;
2923  }
2924 
2925  pageid++;
2926  bg_arv_info->current_page_id = pageid;
2927  }
2928 
2929  assert_release (bg_arv_info->current_page_id >= bg_arv_info->last_sync_pageid);
2931  {
2932  /* System volume. No need to sync DWB. */
2933  fileio_synchronize (thread_p, bg_arv_info->vdes, log_Name_bg_archive, FILEIO_SYNC_ONLY);
2934  bg_arv_info->last_sync_pageid = bg_arv_info->current_page_id;
2935  }
2936 }
2937 
2938 /*
2939  * logpb_append_next_record -
2940  *
2941  * return: NO_ERROR
2942  *
2943  * node(in):
2944  */
2945 static int
2947 {
2948  if (!LSA_EQ (&node->start_lsa, &log_Gl.hdr.append_lsa))
2949  {
2950  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "logpb_append_next_record");
2951  }
2952 
2953  /* forcing flush in the middle of log record append is a complicated business. try to avoid it if possible. */
2954  if (log_Gl.flush_info.num_toflush + 1 >= log_Gl.flush_info.max_toflush) /* flush will be forced on next page */
2955  {
2956  /* flush early to avoid complicated case */
2957  logpb_flush_all_append_pages (thread_p);
2958  }
2959 
2960  logpb_log ("logpb_append_next_record: append a record\n"
2961  "log_Gl.hdr.append_lsa.offset = %d, total record size = %d\n",
2963  sizeof (LOG_RECORD_HEADER) + node->data_header_length + node->ulength + node->rlength);
2964 
2965  /* to tde-encrypt pages which is being created while appending */
2967 
2968  logpb_start_append (thread_p, &node->log_header);
2969 
2970  if (node->data_header != NULL)
2971  {
2973  logpb_append_data (thread_p, node->data_header_length, node->data_header);
2974  }
2975 
2976  if (node->udata != NULL)
2977  {
2978  logpb_append_data (thread_p, node->ulength, node->udata);
2979  }
2980 
2981  if (node->rdata != NULL)
2982  {
2983  logpb_append_data (thread_p, node->rlength, node->rdata);
2984  }
2985 
2986  logpb_end_append (thread_p, &node->log_header);
2987 
2989 
2990  return NO_ERROR;
2991 }
2992 
2993 /*
2994  * logpb_append_prior_lsa_list -
2995  *
2996  * return: NO_ERROR
2997  *
2998  * list(in/out):
2999  */
3000 static int
3002 {
3003  LOG_PRIOR_NODE *node;
3004 
3005  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
3006 
3007  /* append prior_flush_list */
3010 
3011  /* append log buffer */
3013  {
3016 
3017  logpb_append_next_record (thread_p, node);
3018 
3019  if (node->data_header != NULL)
3020  {
3021  free_and_init (node->data_header);
3022  }
3023  if (node->udata != NULL)
3024  {
3025  free_and_init (node->udata);
3026  }
3027  if (node->rdata != NULL)
3028  {
3029  free_and_init (node->rdata);
3030  }
3031 
3032  free_and_init (node);
3033  }
3034 
3035  return NO_ERROR;
3036 }
3037 
3038 /*
3039  * prior_lsa_remove_prior_list:
3040  *
3041  * return: prior list
3042  *
3043  */
3044 static LOG_PRIOR_NODE *
3046 {
3047  LOG_PRIOR_NODE *prior_list;
3048 
3049  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
3050 
3051  prior_list = log_Gl.prior_info.prior_list_header;
3052 
3056 
3057  return prior_list;
3058 }
3059 
3060 /*
3061  * logpb_prior_lsa_append_all_list:
3062  *
3063  * return: NO_ERROR
3064  *
3065  */
3066 int
3068 {
3069  LOG_PRIOR_NODE *prior_list;
3070  INT64 current_size;
3071 
3072  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
3073 
3075  current_size = log_Gl.prior_info.list_size;
3076  prior_list = prior_lsa_remove_prior_list (thread_p);
3077  log_Gl.prior_info.prior_lsa_mutex.unlock ();
3078 
3079  if (prior_list != NULL)
3080  {
3081  perfmon_add_stat (thread_p, PSTAT_PRIOR_LSA_LIST_SIZE, (unsigned int) current_size / ONE_K); /* kbytes */
3083 
3084  logpb_append_prior_lsa_list (thread_p, prior_list);
3085  }
3086 
3087  return NO_ERROR;
3088 }
3089 
3090 /*
3091  * logpb_dump_log_page_area - Dump log page area.
3092  *
3093  * return: nothing
3094  * log_pgptr(in): log page
3095  * offset(in): offset in page area to start logging
3096  * length(in): length to log
3097  */
3098 void
3099 logpb_dump_log_page_area (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, int offset, int length)
3100 {
3101  const int block_size = 4 * ONE_K;
3102  char log_block_string[block_size * 4], log_header_string[200], *src_ptr, *dest_ptr;
3103  int count_remaining_bytes, count_bytes_to_dump, i;
3104  int line_no = 0;
3105 
3106  if (logpb_Logging == false)
3107  {
3108  return;
3109  }
3110 
3111  assert (log_pgptr != NULL);
3112  if (offset < 0 || length < 0 || length > LOGAREA_SIZE || offset + length > LOGAREA_SIZE)
3113  {
3114  return;
3115  }
3116 
3117  sprintf (log_header_string, "page_id = %lld, checksum = %d, offset = %d, length = %d\n",
3118  (long long int) log_pgptr->hdr.logical_pageid, log_pgptr->hdr.checksum, offset, length);
3119 
3120  count_remaining_bytes = length;
3121  src_ptr = log_pgptr->area + offset;
3122  while (count_remaining_bytes > 0)
3123  {
3124  dest_ptr = log_block_string;
3125  count_bytes_to_dump = MIN (count_remaining_bytes, block_size);
3126  for (i = 0; i < count_bytes_to_dump; i++, src_ptr++)
3127  {
3128  if (i % 32 == 0)
3129  {
3130  dest_ptr += sprintf (dest_ptr, "\n %05d: ", line_no++);
3131  }
3132 
3133  dest_ptr += sprintf (dest_ptr, "%02X ", (unsigned char) (*src_ptr));
3134  }
3135 
3136  dest_ptr += sprintf (dest_ptr, "\n");
3137  logpb_log ("logpb_dump_log_page_area: header = %s data = %s\n", log_header_string, log_block_string);
3138  count_remaining_bytes -= count_bytes_to_dump;
3139  }
3140 }
3141 
3142 /*
3143  * logpb_page_get_first_null_block_lsa - Get LSA of first null block in log page.
3144  *
3145  * return: nothing
3146  * thread_p(in): thread entry
3147  * log_pgptr(in): log page
3148  * first_null_block_lsa(out): LSA of first null block.
3149  */
3150 void
3151 logpb_page_get_first_null_block_lsa (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, LOG_LSA * first_null_block_lsa)
3152 {
3153  const int block_size = 4 * ONE_K;
3154  char null_buffer[block_size + MAX_ALIGNMENT], *null_block;
3155  int i, max_num_blocks = LOG_PAGESIZE / block_size;
3156 
3157  assert (log_pgptr != NULL && first_null_block_lsa != NULL);
3158 
3159  null_block = PTR_ALIGN (null_buffer, MAX_ALIGNMENT);
3160  memset (null_block, LOG_PAGE_INIT_VALUE, block_size);
3161 
3162  LSA_SET_NULL (first_null_block_lsa);
3163 
3164  /* Set LSA of first NULL block. */
3165  for (i = 0; i < max_num_blocks; i++)
3166  {
3167  /* Search for null blocks. */
3168  if (memcmp (((char *) log_pgptr) + (i * block_size), null_block, block_size) == 0)
3169  {
3170  /* Found the null block. Computes its LSA. */
3171  first_null_block_lsa->pageid = log_pgptr->hdr.logical_pageid;
3172  first_null_block_lsa->offset = i * block_size;
3173 
3174  if (first_null_block_lsa->offset > 0)
3175  {
3176  /* Skip log header size. */
3177  first_null_block_lsa->offset -= sizeof (LOG_HDRPAGE);
3178  }
3179 
3180  assert (first_null_block_lsa->offset >= 0);
3181  break;
3182  }
3183  }
3184 }
3185 
3186 /*
3187  * logpb_flush_all_append_pages - Flush log append pages
3188  *
3189  * return: 1 : log flushed, 0 : do not need log flush, < 0 : error code
3190  *
3191  */
3192 static int
3194 {
3195  LOG_BUFFER *bufptr = NULL; /* The current buffer log append page scanned */
3196  LOG_BUFFER *prv_bufptr = NULL; /* The previous buffer log append page scanned */
3197  int idxflush; /* An index into the first log page buffer to flush */
3198  bool need_sync; /* How we flush anything ? */
3199 
3200  int i;
3201  LOG_PAGEID first_append_pageid = NULL_PAGEID;
3202  bool need_flush = true;
3203  int error_code = NO_ERROR;
3204  int flush_page_count = 0;
3205 #if defined(CUBRID_DEBUG)
3206  struct timeval start_time = { 0, 0 };
3207  struct timeval end_time = { 0, 0 };
3208  int dirty_page_count = 0;
3209  int curr_flush_count = 0;
3210  long commit_count = 0;
3211  static long prev_commit_count_in_flush = 0;
3212 #endif /* CUBRID_DEBUG */
3213  bool hold_flush_mutex = false;
3214  LOG_FLUSH_INFO *flush_info = &log_Gl.flush_info;
3215  LOG_LSA nxio_lsa;
3216 
3217  int rv;
3218 #if defined(SERVER_MODE)
3219  INT64 flush_start_time = 0;
3220  INT64 flush_completed_time = 0;
3221  INT64 all_writer_thr_end_time = 0;
3222 
3223  LOGWR_INFO *writer_info = log_Gl.writer_info;
3224  LOGWR_ENTRY *entry = NULL;
3225  THREAD_ENTRY *wait_thread_p = NULL;
3226 #endif /* SERVER_MODE */
3227 
3228  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
3229 
3230  logpb_log ("called logpb_flush_all_append_pages\n");
3231 
3232 #if defined(CUBRID_DEBUG)
3233  er_log_debug (ARG_FILE_LINE, "logpb_flush_all_append_pages: start\n");
3234 
3235  gettimeofday (&start_time, NULL);
3236 #endif /* CUBRID_DEBUG */
3237 
3238  rv = pthread_mutex_lock (&flush_info->flush_mutex);
3239  hold_flush_mutex = true;
3240 
3241  if (flush_info->num_toflush < 1)
3242  {
3243  need_flush = false;
3244  }
3245  else if (flush_info->num_toflush == 1)
3246  {
3247  /*
3248  * Don't need to do anything if the page is not dirty.
3249  *
3250  * This block is used to avoid updating the last page with an end of file log when it is not needed at all.
3251  */
3252 
3253  bufptr = logpb_get_log_buffer (flush_info->toflush[0]);
3254  if (!logpb_is_dirty (thread_p, flush_info->toflush[0]))
3255  {
3256  need_flush = false;
3257  }
3258  }
3259 
3260  pthread_mutex_unlock (&flush_info->flush_mutex);
3261  hold_flush_mutex = false;
3262 
3263  if (!need_flush)
3264  {
3265  return 0;
3266  }
3267 
3268 #if !defined(NDEBUG)
3269  {
3270  const char *env_value;
3271  int verbose_dump = -1;
3272 
3273  if (verbose_dump == -1)
3274  {
3275  /*
3276  * Do we want to dump the buffer pool for future verification
3277  */
3278  if ((env_value = envvar_get ("LOG_FLUSH_VERBOSE_DUMP")) != NULL)
3279  {
3280  verbose_dump = atoi (env_value) != 0 ? 1 : 0;
3281  }
3282  else
3283  {
3284  verbose_dump = 0;
3285  }
3286  }
3287 
3288  if (verbose_dump != 0)
3289  {
3290  fprintf (stdout, "\n DUMP BEFORE FLUSHING APPEND PAGES\n");
3291  logpb_dump (thread_p, stdout);
3292  }
3293  }
3294 #endif
3295 
3296 #if defined(SERVER_MODE)
3297  if (thread_p && thread_p->type != TT_DAEMON && thread_p->type != TT_VACUUM_MASTER
3298  && thread_p->type != TT_VACUUM_WORKER)
3299  {
3300  /* set event logging parameter */
3301  thread_p->event_stats.trace_log_flush_time = prm_get_integer_value (PRM_ID_LOG_TRACE_FLUSH_TIME_MSECS);
3302  }
3303 #endif /* SERVER_MODE */
3304 
3305 #if defined(CUBRID_DEBUG)
3306  if (log_Gl.append.get_nxio_lsa ().pageid != logpb_get_page_id (flush_info->toflush[0]))
3307  {
3309  "logpb_flush_all_append_pages: SYSTEM ERROR\n NXIO_PAGE %d does not seem the same as next free"
3310  " append page %d to flush\n", log_Gl.append.get_nxio_lsa ().pageid,
3311  logpb_get_page_id (flush_info->toflush[0]));
3312  goto error;
3313  }
3314 #endif /* CUBRID_DEBUG */
3315 
3316  /* how this works:
3317  * ok, so we might have to flush several pages here. if there is only one page, the implementation is straight
3318  * forward, just flush the page.
3319  *
3320  * however, if there are two or more pages, we really need to make sure that the first page, where previous end of log
3321  * record resides (where nxio_lsa points), is flushed last! we cannot validate the new end of log record until we are
3322  * sure all log pages have been flushed!
3323  * so, we'll do a two-step flushing: in the first step we skip nxio_lsa page and flush all other pages. in the second
3324  * step we flush the nxio_lsa page.
3325  *
3326  * the story becomes a lot more complicated when a log entry is only partially appended before flush is called. this
3327  * can happen for when log page buffer becomes full. the problem here is that we cannot yet validate the flushed pages
3328  * before flushing this record entirely; not all pages. what we do here is replace the incomplete record with end of
3329  * log record (very important! not in log page buffer, but in a copy of the log page; that way we allow others to read
3330  * the correct version from buffer). the overwritten copy is flushed to disk.
3331  * when the log record is fully appended (there can be several iterations of flush if we deal with a very large log
3332  * record and log page buffer is very small), we call again flush again to make sure all remaining record pages are
3333  * written to disk. at the end of this flush iteration, the original record is written back and page is flushed again,
3334  * validating new record.
3335  *
3336  * to see full implementation, follow references of log_Pb.partial_append.
3337  *
3338  * todo: we might think of a better and simpler solution. the most difficult case to handle is very large log record,
3339  * larger than log page buffer. since log records can theoretically be any size, the solution will have to
3340  * consider this case.
3341  * for now I chose a solution similar to the implementation used before the log page buffer redesign.
3342  */
3343 
3344  /*
3345  * Add an end of log marker to detect the end of the log.
3346  * The marker should be added at the end of the log if there is only one page to be flushed.
3347  * That is, if we are not in the middle of appending a new log record. Otherwise, we need to change the label of
3348  * the last append record as log end record. Flush and then check it back.
3349  */
3350 
3352  {
3353  /* Flush all log append records on such page except the current log record which has not been finished.
3354  * Save the log record type of this record, overwrite an eof record on such position, and flush the page.
3355  * Then, restore the record back on the page and change the current append log sequence address.
3356  */
3357  logpb_log ("logpb_flush_all_append_pages: incomplete record at log_Gl.append.prev_lsa=%lld|%d when flush is "
3358  "called. we'll overwrite the log record with eof.\n", (long long int) log_Gl.append.prev_lsa.pageid,
3359  (int) log_Gl.append.prev_lsa.offset);
3360 
3361  /* first, let's see if this is page is still in log page buffer */
3362  first_append_pageid = log_Gl.append.prev_lsa.pageid;
3363  bufptr = &log_Pb.buffers[logpb_get_log_buffer_index (first_append_pageid)];
3364 
3365  if (bufptr->pageid != first_append_pageid)
3366  {
3367  assert_release (false);
3368  logpb_log ("logpb_flush_all_append_pages: fatal error, partial page not found in log page buffer.");
3369  error_code = ER_FAILED;
3370  goto error;
3371  }
3372 
3373  /* copy from log page buffer */
3374  memcpy (log_Pb.partial_append.log_page_record_header, bufptr->logpage, LOG_PAGESIZE);
3375 
3376  /* set entry in log page buffer not dirty. we don't want it to get flushed again */
3377  bufptr->dirty = false;
3378 
3379  /* Overwrite it with an end of log marker */
3385 
3386  /* write page to disk as it is */
3387  if (logpb_write_page_to_disk (thread_p, log_Pb.partial_append.log_page_record_header, first_append_pageid)
3388  != NO_ERROR)
3389  {
3390  error_code = ER_FAILED;
3391  goto error;
3392  }
3394 
3396  }
3398  {
3399  logpb_log ("logpb_flush_all_append_pages: continue flushing page of partially appended log record.\n");
3400  }
3403  {
3404  /* Add an end of log marker to detect the end of the log.
3405  * Don't advance the log address, the log end of file is overwritten at a later point. */
3406  LOG_RECORD_HEADER eof;
3407 
3408  logpb_log ("logpb_flush_all_append_pages: append end of log record at append_lsa = %lld|%d.\n",
3409  (long long int) log_Gl.hdr.append_lsa.pageid, (int) log_Gl.hdr.append_lsa.offset);
3410  eof.trid = LOG_READ_NEXT_TRANID;
3411  LSA_SET_NULL (&eof.prev_tranlsa);
3413  LSA_SET_NULL (&eof.forw_lsa);
3414  eof.type = LOG_END_OF_LOG;
3415 
3416  logpb_start_append (thread_p, &eof);
3417  }
3418  else
3419  {
3420  /* unexpected status here */
3421  assert_release (false);
3422  error_code = ER_FAILED;
3423  goto error;
3424  }
3425 
3426  /*
3427  * Now flush all contiguous log append dirty pages. The first log append dirty page is flushed at the end,
3428  * so we can synchronize it with the rest.
3429  */
3430 
3431 #if defined(SERVER_MODE)
3432  /* It changes the status of waiting log writer threads and wakes them up */
3433  if (!HA_DISABLED () && !writer_info->skip_flush)
3434  {
3435  assert (hold_flush_mutex == false);
3436  LOG_CS_DEMOTE (thread_p);
3437 
3438  rv = pthread_mutex_lock (&writer_info->flush_start_mutex);
3439  rv = pthread_mutex_lock (&writer_info->wr_list_mutex);
3440 
3441  if (thread_p != NULL && thread_p->event_stats.trace_log_flush_time > 0)
3442  {
3443  flush_start_time = log_get_clock_msec ();
3444 
3445  // *INDENT-OFF*
3446  new (&writer_info->last_writer_client_info) clientids ();
3447  // *INDENT-ON*
3448 
3449  writer_info->trace_last_writer = true;
3450  writer_info->last_writer_elapsed_time = 0;
3452  }
3453 
3454  entry = writer_info->writer_list;
3455  while (entry)
3456  {
3457  if (entry->status == LOGWR_STATUS_WAIT)
3458  {
3459  wait_thread_p = entry->thread_p;
3460  assert (wait_thread_p != thread_p);
3461 
3462  thread_lock_entry (wait_thread_p);
3463 
3464  /* If THREAD_RESUME_DUE_TO_INTERRUPT, do not set the entry status to avoid deadlock
3465  * between flush_end_cond and CSECT_LOG.
3466  */
3467  if (thread_p->resume_status != THREAD_RESUME_DUE_TO_INTERRUPT)
3468  {
3469  /* Still waiting for LOGWR. */
3470  entry->status = LOGWR_STATUS_FETCH;
3471  if (wait_thread_p->resume_status == THREAD_LOGWR_SUSPENDED)
3472  {
3474  }
3475  }
3476 
3477  thread_unlock_entry (wait_thread_p);
3478  }
3479  entry = entry->next;
3480  }
3481 
3482  rv = pthread_mutex_lock (&writer_info->flush_wait_mutex);
3483  writer_info->flush_completed = false;
3484  rv = pthread_mutex_unlock (&writer_info->flush_wait_mutex);
3485 
3486  pthread_mutex_unlock (&writer_info->wr_list_mutex);
3487  pthread_mutex_unlock (&writer_info->flush_start_mutex);
3488  }
3489 #endif /* SERVER_MODE */
3490 
3491  idxflush = -1;
3492  prv_bufptr = NULL;
3493  need_sync = false;
3494 
3495  rv = pthread_mutex_lock (&flush_info->flush_mutex);
3496  hold_flush_mutex = true;
3497 
3498 #if defined(CUBRID_DEBUG)
3499  log_scan_flush_info (log_dump_pageid);
3500  er_log_debug (ARG_FILE_LINE, "\n");
3501 #endif /* CUBRID_DEBUG */
3502 
3503  /* Record number of writes in statistics */
3504  perfmon_add_stat (thread_p, PSTAT_LOG_NUM_IOWRITES, flush_info->num_toflush);
3505 
3506  /* loop through all to flush list. do a two-step process:
3507  * 1. skip all pages not dirty. also skip the page of nxio_lsa! it must be flushed last!
3508  * 2. collect and flush all dirty and successive pages.
3509  */
3510  i = 0;
3511  while (true)
3512  {
3513  /* skip all not dirty */
3514  for (; i < flush_info->num_toflush; i++)
3515  {
3516  bufptr = logpb_get_log_buffer (flush_info->toflush[i]);
3517  assert (bufptr->pageid == flush_info->toflush[i]->hdr.logical_pageid);
3518  if (bufptr->dirty && bufptr->pageid != log_Gl.append.get_nxio_lsa ().pageid)
3519  {
3520  /* found dirty */
3521  break;
3522  }
3523  logpb_log ("logpb_flush_all_append_pages: skip flushing not dirty page %lld.\n", bufptr->pageid);
3524  }
3525  if (i == flush_info->num_toflush)
3526  {
3527  /* nothing left to flush */
3528  break;
3529  }
3530 
3531  /* we have a dirty record */
3532  assert (bufptr->dirty);
3533  prv_bufptr = bufptr;
3534  idxflush = i;
3535 
3536  /* advance to next */
3537  i++;
3538 
3539  /* collect all consecutive pages that are dirty */
3540  for (; i < flush_info->num_toflush; i++)
3541  {
3542  bufptr = logpb_get_log_buffer (flush_info->toflush[i]);
3543 
3544  assert (bufptr->pageid == flush_info->toflush[i]->hdr.logical_pageid);
3545 
3546  if (!bufptr->dirty)
3547  {
3548  /* not dirty */
3549  break;
3550  }
3551  if (bufptr->pageid == log_Gl.append.get_nxio_lsa ().pageid)
3552  {
3553  /* this must be flushed last! */
3554  break;
3555  }
3556  if (prv_bufptr->pageid + 1 != bufptr->pageid)
3557  {
3558  /* not successive pages */
3559  break;
3560  }
3561  if (prv_bufptr->phy_pageid + 1 != bufptr->phy_pageid)
3562  {
3563  /* not successive pages on disk */
3564  break;
3565  }
3566 
3567  prv_bufptr = bufptr;
3568  }
3569 
3570  if (logpb_writev_append_pages (thread_p, &flush_info->toflush[idxflush], i - idxflush) == NULL)
3571  {
3572  /* is this acceptable? */
3573  assert_release (false);
3574  error_code = ER_FAILED;
3575  goto error;
3576  }
3577  else
3578  {
3579  int buf_iter;
3580  need_sync = true;
3581  flush_page_count += i - idxflush;
3582 
3583  logpb_log ("logpb_flush_all_append_pages: flushed all pages in range [%lld, %lld].\n",
3584  (long long int) flush_info->toflush[idxflush]->hdr.logical_pageid,
3585  (long long int) flush_info->toflush[idxflush]->hdr.logical_pageid + i - idxflush - 1);
3586 
3587  /* set not dirty what we have flushed */
3588  for (buf_iter = idxflush; buf_iter < i; buf_iter++)
3589  {
3590  bufptr = logpb_get_log_buffer (flush_info->toflush[buf_iter]);
3591  bufptr->dirty = false;
3592  }
3593 #if defined (CUBRID_DEBUG)
3594  dirty_page_count += i - idxflush;
3595 #endif /* CUBRID_DEBUG */
3596  }
3597 
3598  if (i == flush_info->num_toflush)
3599  {
3600  /* nothing left to flush */
3601  break;
3602  }
3603  }
3604 
3605  /* now flush the nxio_lsa page... unless it is the page of header for incomplete log record */
3606  nxio_lsa = log_Gl.append.get_nxio_lsa ();
3608  {
3611 
3612  bufptr = &log_Pb.buffers[logpb_get_log_buffer_index (nxio_lsa.pageid)];
3613 
3614  if (bufptr->pageid != nxio_lsa.pageid)
3615  {
3616  /* not expected. */
3617  assert_release (false);
3618 
3619  logpb_log ("logpb_flush_all_append_pages: fatal error, nxio_lsa %lld|%d page not found in buffer. "
3620  "bufptr->pageid is %lld instead.\n",
3621  (long long int) nxio_lsa.pageid, (int) nxio_lsa.offset, (long long int) bufptr->pageid);
3622 
3623  error_code = ER_FAILED;
3624  goto error;
3625  }
3626 
3627  if (!bufptr->dirty)
3628  {
3629  /* not expected */
3630  assert_release (false);
3631 
3632  logpb_log ("logpb_flush_all_append_pages: fatal error, nxio_lsa %lld|%d page is not dirty.\n",
3633  (long long int) nxio_lsa.pageid, (int) nxio_lsa.offset);
3634 
3635  error_code = ER_FAILED;
3636  goto error;
3637  }
3638 
3639  logpb_write_page_to_disk (thread_p, bufptr->logpage, bufptr->pageid);
3640  need_sync = true;
3641  bufptr->dirty = false;
3642  flush_page_count += 1;
3643 
3644  logpb_log ("logpb_flush_all_append_pages: flushed nxio_lsa = %lld|%d page to disk.\n",
3645  (long long int) log_Gl.append.get_nxio_lsa ().pageid, (int) log_Gl.append.get_nxio_lsa ().offset);
3646 
3647  if (logpb_Logging)
3648  {
3649  /* Dump latest portion of page, for debugging purpose. */
3650  logpb_dump_log_page_area (thread_p, bufptr->logpage, (int) (log_Gl.append.get_nxio_lsa ().offset),
3651  (int) sizeof (LOG_RECORD_HEADER));
3652  logpb_dump_log_page_area (thread_p, bufptr->logpage, (int) (log_Gl.hdr.eof_lsa.offset),
3653  (int) sizeof (LOG_RECORD_HEADER));
3654  }
3655  }
3656  else
3657  {
3658  logpb_log ("logpb_flush_all_append_pages: skipped flushing nxio_lsa = %lld|%d page to disk because it matches "
3659  "the header page for incomplete record (prev_lsa = %lld|%d).\n",
3660  (long long int) log_Gl.append.get_nxio_lsa ().pageid, (int) log_Gl.append.get_nxio_lsa ().offset,
3661  (long long int) log_Gl.append.prev_lsa.pageid, (int) log_Gl.append.prev_lsa.offset);
3662  }
3663 
3664  /* Make sure that all of the above log writes are synchronized with any future log writes.
3665  * That is, the pages should be stored on physical disk.
3666  */
3667  if (need_sync == true)
3668  {
3671  {
3672  /* System volume. No need to sync DWB. */
3674  {
3675  error_code = ER_FAILED;
3676  goto error;
3677  }
3678  log_Stat.total_sync_count++;
3679  }
3680  }
3681 
3682  /* dual writing (Background archiving) */
3684  {
3686  }
3687 
3688 #if !defined(NDEBUG)
3689  if (prm_get_bool_value (PRM_ID_LOG_TRACE_DEBUG) && logpb_is_any_dirty (thread_p) == true)
3690  {
3691  er_log_debug (ARG_FILE_LINE, "logpb_flush_all_append_pages: Log Buffer contains dirty pages\n");
3692  logpb_dump (thread_p, stdout);
3693  fflush (stdout);
3694  }
3695 #endif
3696 
3697  if (flush_info->num_toflush == flush_info->max_toflush)
3698  {
3699  log_Stat.log_buffer_full_count++;
3700  }
3701 #if defined(CUBRID_DEBUG)
3702  curr_flush_count = flush_info->num_toflush;
3703 #endif /* CUBRID_DEBUG */
3704 
3705  /*
3706  * Change the log sequence address to indicate the next append address to flush and synchronize
3707  */
3709  {
3710  /* partially flushed log record is now complete */
3711 
3712  /* overwrite with original log record. */
3714  error_code =
3717  if (error_code != NO_ERROR)
3718  {
3719  goto error;
3720  }
3721  ++flush_page_count;
3722 
3723  /* Update checksum. */
3724  first_append_pageid = log_Pb.partial_append.log_page_record_header->hdr.logical_pageid;
3725  bufptr = &log_Pb.buffers[logpb_get_log_buffer_index (first_append_pageid)];
3726  if (bufptr->pageid == first_append_pageid)
3727  {
3729  assert (!memcmp (bufptr->logpage, log_Pb.partial_append.log_page_record_header, LOG_PAGESIZE));
3730 #if !defined(NDEBUG)
3731  logpb_debug_check_log_page (thread_p, bufptr->logpage);
3732 #endif
3733  }
3734 
3735  /* we need to also sync again */
3737  {
3738  error_code = ER_FAILED;
3739  goto error;
3740  }
3741 
3742  /* now we can set the nxio_lsa to append_lsa */
3744 
3746 
3747  logpb_log ("logpb_flush_all_append_pages: completed partial record and flush again its first page %lld. "
3748  "nxio_lsa = %lld|%d.\n",
3749  (long long int) log_Pb.partial_append.log_page_record_header->hdr.logical_pageid,
3750  (long long int) log_Gl.append.get_nxio_lsa ().pageid, (int) log_Gl.append.get_nxio_lsa ().offset);
3751  }
3753  {
3754  /* we cannot set nxio_lsa to append_lsa yet. set it to append.prev_lsa */
3756 
3757  logpb_log ("logpb_flush_all_append_pages: partial record flushed... set nxio_lsa = %lld|%d.\n",
3758  (long long int) log_Gl.append.get_nxio_lsa ().pageid, (int) log_Gl.append.get_nxio_lsa ().offset);
3759  }
3760  else if (log_Pb.partial_append.status == LOGPB_APPENDREC_SUCCESS)
3761  {
3763 
3764  logpb_log ("logpb_flush_all_append_pages: set nxio_lsa = %lld|%d.\n",
3765  (long long int) log_Gl.append.get_nxio_lsa ().pageid, (int) log_Gl.append.get_nxio_lsa ().offset);
3766  }
3767  else
3768  {
3769  /* unexpected */
3770  assert_release (false);
3771  error_code = ER_FAILED;
3772  goto error;
3773  }
3774  flush_info->num_toflush = 0;
3775 
3776  if (log_Gl.append.log_pgptr != NULL)
3777  {
3778  /* Add the append page */
3779  flush_info->toflush[flush_info->num_toflush] = log_Gl.append.log_pgptr;
3780  flush_info->num_toflush++;
3781  }
3782 
3784  log_Stat.last_flush_count_by_trans = flush_page_count;
3785  log_Stat.total_flush_count_by_trans += flush_page_count;
3786 
3787 #if defined(CUBRID_DEBUG)
3788  gettimeofday (&end_time, NULL);
3789 
3790  log_Stat.last_flush_sec_by_trans = LOG_GET_ELAPSED_TIME (end_time, start_time);
3791 
3793 
3794  commit_count = log_Stat.commit_count - prev_commit_count_in_flush;
3795  prev_commit_count_in_flush = log_Stat.commit_count;
3796 
3797  log_Stat.last_commit_count_in_flush_pages = commit_count;
3799 
3801  "logpb_flush_all_append_pages: flush page(%ld / %d / %ld) avg flush count(%f), avg flush sec(%f)"
3802  "commit count(%ld) avg commit count(%f)\n", log_Stat.last_flush_count_by_trans, dirty_page_count,
3803  curr_flush_count,
3804  (double) log_Stat.total_flush_count_by_trans / log_Stat.flushall_append_pages_call_count,
3805  log_Stat.total_flush_sec_by_trans / log_Stat.flushall_append_pages_call_count, commit_count,
3807 #endif /* CUBRID_DEBUG */
3808 
3809  pthread_mutex_unlock (&flush_info->flush_mutex);
3810  hold_flush_mutex = false;
3811 
3812 #if defined(SERVER_MODE)
3813  if (!HA_DISABLED () && !writer_info->skip_flush)
3814  {
3815  /* it sends signal to LWT to notify that flush is completed */
3816  rv = pthread_mutex_lock (&writer_info->flush_wait_mutex);
3817 
3818  if (thread_p != NULL && thread_p->event_stats.trace_log_flush_time > 0)
3819  {
3820  flush_completed_time = log_get_clock_msec ();
3821  }
3822 
3823  writer_info->flush_completed = true;
3824  rv = pthread_cond_broadcast (&writer_info->flush_wait_cond);
3825 
3826  rv = pthread_mutex_unlock (&writer_info->flush_wait_mutex);
3827 
3828  /* It waits until all log writer threads are done */
3829  rv = pthread_mutex_lock (&writer_info->flush_end_mutex);
3830 
3831  rv = pthread_mutex_lock (&writer_info->wr_list_mutex);
3832  entry = writer_info->writer_list;
3833  while (entry != NULL)
3834  {
3835  if (entry->status == LOGWR_STATUS_FETCH)
3836  {
3837  break;
3838  }
3839  entry = entry->next;
3840  }
3841  pthread_mutex_unlock (&writer_info->wr_list_mutex);
3842 
3843  if (entry != NULL)
3844  {
3845  rv = pthread_cond_wait (&writer_info->flush_end_cond, &writer_info->flush_end_mutex);
3846  }
3847 
3848  rv = pthread_mutex_lock (&writer_info->wr_list_mutex);
3849  writer_info->trace_last_writer = false;
3850 
3851  if (thread_p != NULL && thread_p->event_stats.trace_log_flush_time > 0)
3852  {
3853  all_writer_thr_end_time = log_get_clock_msec ();
3854 
3855  if (all_writer_thr_end_time - flush_start_time > thread_p->event_stats.trace_log_flush_time)
3856  {
3857  event_log_log_flush_thr_wait (thread_p, flush_page_count, &writer_info->last_writer_client_info,
3858  (int) (all_writer_thr_end_time - flush_start_time),
3859  (int) (all_writer_thr_end_time - flush_completed_time),
3860  (int) writer_info->last_writer_elapsed_time);
3861  }
3862  }
3863 
3864  pthread_mutex_unlock (&writer_info->wr_list_mutex);
3865 
3866  pthread_mutex_unlock (&writer_info->flush_end_mutex);
3867  assert (hold_flush_mutex == false);
3868  LOG_CS_PROMOTE (thread_p);
3869  }
3870 #endif /* SERVER_MODE */
3871 
3872 #if defined(SERVER_MODE)
3873  if (thread_p && thread_p->type != TT_DAEMON && thread_p->type != TT_VACUUM_MASTER
3874  && thread_p->type != TT_VACUUM_WORKER)
3875  {
3876  /* reset event logging parameter */
3877  thread_p->event_stats.trace_log_flush_time = 0;
3878  }
3879 #endif /* SERVER_MODE */
3880 
3881  return 1;
3882 
3883 error:
3884  if (hold_flush_mutex)
3885  {
3886  pthread_mutex_unlock (&flush_info->flush_mutex);
3887  }
3888 
3889  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "logpb_flush_all_append_pages");
3890 
3891 #if defined(SERVER_MODE)
3892  if (thread_p && thread_p->type != TT_DAEMON && thread_p->type != TT_VACUUM_MASTER
3893  && thread_p->type != TT_VACUUM_WORKER)
3894  {
3895  /* reset event logging parameter */
3896  thread_p->event_stats.trace_log_flush_time = 0;
3897  }
3898 #endif /* SERVER_MODE */
3899 
3900  return error_code;
3901 }
3902 
3903 /*
3904  * logpb_flush_pages_direct - flush all pages by itself.
3905  *
3906  * return: nothing
3907  *
3908  */
3909 void
3911 {
3912 #if defined(CUBRID_DEBUG)
3913  er_log_debug (ARG_FILE_LINE, "logpb_flush_pages_direct: [%d]flush direct\n", (int) THREAD_ID ());
3914 #endif /* CUBRID_DEBUG */
3915 
3916  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
3917 
3919  (void) logpb_flush_all_append_pages (thread_p);
3920  log_Stat.direct_flush_count++;
3921 }
3922 
3923 /*
3924  * logpb_flush_pages - FLUSH LOG APPEND PAGES
3925  *
3926  * return: nothing
3927  *
3928  * flush_lsa(in):
3929  *
3930  * NOTE:There are 4 cases to commit.
3931  * ASYNC | GROUP COMMIT
3932  * X X : normal commit, wakeup LFT and wait
3933  * X O : group commit, wait
3934  * O X : async commit, wakeup LFT and return
3935  * O O : async & group commit, just return
3936  */
3937 void
3938 logpb_flush_pages (THREAD_ENTRY * thread_p, LOG_LSA * flush_lsa)
3939 {
3940 #if !defined(SERVER_MODE)
3941  LOG_CS_ENTER (thread_p);
3942  logpb_flush_pages_direct (thread_p);
3943  LOG_CS_EXIT (thread_p);
3944 #else /* SERVER_MODE */
3945  int rv;
3946  struct timeval start_time = { 0, 0 };
3947  struct timeval tmp_timeval = { 0, 0 };
3948  struct timespec to = { 0, 0 };
3949  int max_wait_time_in_msec = 1000;
3950  bool need_wakeup_LFT, need_wait;
3951  bool async_commit, group_commit;
3952  LOG_LSA nxio_lsa;
3953  LOG_GROUP_COMMIT_INFO *group_commit_info = &log_Gl.group_commit_info;
3954 
3955  assert (flush_lsa != NULL && !LSA_ISNULL (flush_lsa));
3956 
3957  if (!BO_IS_SERVER_RESTARTED () || flush_lsa == NULL || LSA_ISNULL (flush_lsa))
3958  {
3959  LOG_CS_ENTER (thread_p);
3960  logpb_flush_pages_direct (thread_p);
3961  LOG_CS_EXIT (thread_p);
3962 
3963  return;
3964  }
3965  assert (!LOG_CS_OWN_WRITE_MODE (thread_p));
3966 
3968  {
3969  LOG_CS_ENTER (thread_p);
3970  logpb_flush_pages_direct (thread_p);
3971  LOG_CS_EXIT (thread_p);
3972 
3973  return;
3974  }
3975 
3977  group_commit = LOG_IS_GROUP_COMMIT_ACTIVE ();
3978 
3979  if (async_commit == false)
3980  {
3981  need_wait = true;
3982  if (group_commit == false)
3983  {
3984  /* Default case: synchorous & non-group commit */
3985  need_wakeup_LFT = true;
3986  }
3987  else
3988  {
3989  /* synchronous & group commit */
3990  need_wakeup_LFT = false;
3991  log_Stat.gc_commit_request_count++;
3992  }
3993  }
3994  else
3995  {
3996  need_wait = false;
3997  log_Stat.async_commit_request_count++;
3998 
3999  if (group_commit == false)
4000  {
4001  /* asynchorous & non-group commit */
4002  need_wakeup_LFT = true;
4003  }
4004  else
4005  {
4006  /* asynchorous & group commit */
4007  need_wakeup_LFT = false;
4008  log_Stat.gc_commit_request_count++;
4009  }
4010  }
4011 
4012  if (need_wakeup_LFT == true && need_wait == false)
4013  {
4015  }
4016  else if (need_wait == true)
4017  {
4018  nxio_lsa = log_Gl.append.get_nxio_lsa ();
4019 
4020  if (need_wakeup_LFT == false && pgbuf_has_perm_pages_fixed (thread_p))
4021  {
4022  need_wakeup_LFT = true;
4023  }
4024 
4025  while (LSA_LT (&nxio_lsa, flush_lsa))
4026  {
4027  gettimeofday (&start_time, NULL);
4028  (void) timeval_add_msec (&tmp_timeval, &start_time, max_wait_time_in_msec);
4029  (void) timeval_to_timespec (&to, &tmp_timeval);
4030 
4031  rv = pthread_mutex_lock (&group_commit_info->gc_mutex);
4032  nxio_lsa = log_Gl.append.get_nxio_lsa ();
4033  if (LSA_GE (&nxio_lsa, flush_lsa))
4034  {
4035  pthread_mutex_unlock (&group_commit_info->gc_mutex);
4036  break;
4037  }
4038 
4039  if (need_wakeup_LFT == true)
4040  {
4042  }
4043  (void) pthread_cond_timedwait (&group_commit_info->gc_cond, &group_commit_info->gc_mutex, &to);
4044  pthread_mutex_unlock (&group_commit_info->gc_mutex);
4045 
4046  need_wakeup_LFT = true;
4047  nxio_lsa = log_Gl.append.get_nxio_lsa ();
4048  }
4049  }
4050 #endif /* SERVER_MODE */
4051 }
4052 
4053 void
4055 {
4056  LOG_CS_ENTER (thread_p);
4057  logpb_flush_pages_direct (thread_p);
4058  LOG_CS_EXIT (thread_p);
4059 }
4060 
4061 void
4063 {
4064  LOG_CS_ENTER (thread_p);
4065  logpb_flush_pages_direct (thread_p);
4066  logpb_flush_header (thread_p);
4067  LOG_CS_EXIT (thread_p);
4068 }
4069 
4070 /*
4071  * logpb_invalid_all_append_pages - Invalidate all append pages
4072  *
4073  * return: nothing
4074  *
4075  * NOTE:Invalidate and free all append pages. Before invalidating the
4076  * pages if their are dirty, they are flushed.
4077  */
4078 void
4080 {
4081  LOG_FLUSH_INFO *flush_info = &log_Gl.flush_info;
4082 #if defined(SERVER_MODE)
4083  int rv;
4084 #endif /* SERVER_MODE */
4085 
4086  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
4087 
4088  logpb_log ("called logpb_invalid_all_append_pages\n");
4089 
4090  if (log_Gl.append.log_pgptr != NULL)
4091  {
4092  /*
4093  * Somehow we already have an append page, flush all current append page
4094  * and start form scratch
4095  */
4096  logpb_flush_pages_direct (thread_p);
4098  }
4099 
4100  rv = pthread_mutex_lock (&flush_info->flush_mutex);
4101 
4102  flush_info->num_toflush = 0;
4103  flush_info->toflush[flush_info->num_toflush] = NULL;
4104 
4105  pthread_mutex_unlock (&flush_info->flush_mutex);
4106 }
4107 
4108 /*
4109  * logpb_flush_log_for_wal - Flush log if needed
4110  *
4111  * return: nothing
4112  *
4113  * lsa_ptr(in): Force all log records up to this lsa
4114  *
4115  * NOTE:Flush the log up to given log sequence address according to the WAL rule.
4116  * The page buffer manager must call this function whenever a
4117  * page is about to be flushed due to a page replacement.
4118  */
4119 void
4120 logpb_flush_log_for_wal (THREAD_ENTRY * thread_p, const LOG_LSA * lsa_ptr)
4121 {
4122  if (logpb_need_wal (lsa_ptr))
4123  {
4125 
4126  LOG_CS_ENTER (thread_p);
4127  if (logpb_need_wal (lsa_ptr))
4128  {
4129  logpb_flush_pages_direct (thread_p);
4130  }
4131  else
4132  {
4133  /* was flushed in the meantime */
4134  }
4135  LOG_CS_EXIT (thread_p);
4136 
4137  assert (LSA_ISNULL (lsa_ptr) || !logpb_need_wal (lsa_ptr));
4138 
4139 #if defined(CUBRID_DEBUG)
4140  if (logpb_need_wal (lsa_ptr) && !LSA_EQ (&log_Gl.rcv_phase_lsa, lsa_ptr))
4141  {
4142  er_log_debug (ARG_FILE_LINE, "log_wal: SYSTEM ERROR.. DUMP LOG BUFFER\n");
4143  logpb_dump (thread_p, stdout);
4144  }
4145 #endif /* CUBRID_DEBUG */
4146  }
4147 }
4148 
4149 /*
4150  *
4151  * FUNCTIONS RELATED TO DATA APPEND
4152  *
4153  */
4154 
4155 /*
4156  * logpb_start_append - Start appending a new log record
4157  *
4158  * return: nothing
4159  *
4160  * header(in):
4161  *
4162  * NOTE:
4163  */
4164 static void
4166 {
4167  LOG_RECORD_HEADER *log_rec; /* Log record */
4168 
4169  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
4170 
4171  /* Record number of append log record in statistics */
4173 
4174  /* Does the new log record fit in this page ? */
4176 
4177  if (!LSA_EQ (&header->back_lsa, &log_Gl.append.prev_lsa))
4178  {
4179  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "logpb_start_append");
4180  }
4181 
4183 
4185  {
4187  {
4189  logpb_set_tde_algorithm (thread_p, log_Gl.append.log_pgptr, tde_algo);
4190  logpb_set_dirty (thread_p, log_Gl.append.log_pgptr);
4191  logpb_log ("logpb_start_append: set tde_algorithm to existing page (%lld), "
4192  "tde_algorithm = %s\n", (long long int) log_Gl.append.log_pgptr->hdr.logical_pageid,
4193  tde_get_algorithm_name (tde_algo));
4194  }
4195  else
4196  {
4197  logpb_log ("logpb_start_append: tde_algorithm already set to existing page (%lld), "
4198  "tde_algorithm = %s\n", (long long int) log_Gl.append.log_pgptr->hdr.logical_pageid,
4200  }
4201  }
4202 
4203  log_rec = (LOG_RECORD_HEADER *) LOG_APPEND_PTR ();
4204  *log_rec = *header;
4205 
4206  /*
4207  * If the header of the append page does not have the offset set to the
4208  * first log record, this is the first log record in the page, set to it.
4209  */
4210 
4212  {
4214  }
4215 
4216  if (log_rec->type == LOG_END_OF_LOG)
4217  {
4218  /* this comes from logpb_flush_all_append_pages */
4221 
4223 
4224  logpb_set_dirty (thread_p, log_Gl.append.log_pgptr);
4225  }
4226  else
4227  {
4228  /* no record should be in progress now */
4230 
4232 
4233  /*
4234  * Set the page dirty, increase and align the append offset
4235  */
4236  LOG_APPEND_SETDIRTY_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER));
4237 
4239  }
4240 }
4241 
4242 /*
4243  * logpb_append_data - Append data
4244  *
4245  * return: nothing
4246  *
4247  * length(in): Length of data to append
4248  * data(in): Data to append
4249  *
4250  * NOTE:Append data as part of current log record.
4251  */
4252 static void
4253 logpb_append_data (THREAD_ENTRY * thread_p, int length, const char *data)
4254 {
4255  int copy_length; /* Amount of contiguos data that can be copied */
4256  char *ptr; /* Pointer for copy data into log append buffer */
4257  char *last_ptr; /* Pointer to last portion available to copy into log append buffer */
4258 
4259  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
4260 
4261  if (length == 0 || data == NULL)
4262  {
4263  return;
4264  }
4265 
4266  /*
4267  * Align if needed,
4268  * don't set it dirty since this function has not updated
4269  */
4271 
4272  ptr = LOG_APPEND_PTR ();
4273  last_ptr = LOG_LAST_APPEND_PTR ();
4274 
4275  /* Does data fit completely in current page ? */
4276  if ((ptr + length) >= last_ptr)
4277  {
4278  while (length > 0)
4279  {
4280  if (ptr >= last_ptr)
4281  {
4282  /*
4283  * Get next page and set the current one dirty
4284  */
4286  ptr = LOG_APPEND_PTR ();
4287  last_ptr = LOG_LAST_APPEND_PTR ();
4288  }
4289  /* Find the amount of contiguous data that can be copied */
4290  if (ptr + length >= last_ptr)
4291  {
4292  copy_length = CAST_BUFLEN (last_ptr - ptr);
4293  }
4294  else
4295  {
4296  copy_length = length;
4297  }
4298  memcpy (ptr, data, copy_length);
4299  ptr += copy_length;
4300  data += copy_length;
4301  length -= copy_length;
4302  log_Gl.hdr.append_lsa.offset += copy_length;
4303  }
4304  }
4305  else
4306  {
4307  memcpy (ptr, data, length);
4308  log_Gl.hdr.append_lsa.offset += length;
4309  }
4310 
4311  /*
4312  * Align the data for future appends.
4313  * Indicate that modifications were done
4314  */
4315  LOG_APPEND_ALIGN (thread_p, LOG_SET_DIRTY);
4316 }
4317 
4318 /*
4319  * logpb_append_crumbs - Append crumbs of data
4320  *
4321  * return: nothing
4322  *
4323  * num_crumbs(in): Number of crumbs
4324  * crumbs(in): The crumbs (length + data)
4325  *
4326  * NOTE: Append crumbs of data by gluing them. After this the log manager will lose track of what was glued.
4327  */
4328 static void
4329 logpb_append_crumbs (THREAD_ENTRY * thread_p, int num_crumbs, const LOG_CRUMB * crumbs)
4330 {
4331  const char *data; /* Data to copy */
4332  char *ptr; /* Pointer for copy data into log append buffer */
4333  char *last_ptr; /* Pointer to last portion available to copy into log append buffer */
4334  int copy_length; /* Amount of contiguos data that can be copied */
4335  int length;
4336  int i;
4337 
4338  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
4339 
4340  if (num_crumbs == 0)
4341  {
4342  return;
4343  }
4344 
4345  /*
4346  * Align if needed,
4347  * don't set it dirty since this function has not updated
4348  */
4350 
4351  ptr = LOG_APPEND_PTR ();
4352  last_ptr = LOG_LAST_APPEND_PTR ();
4353 
4354  for (i = 0; i < num_crumbs; i++)
4355  {
4356  length = crumbs[i].length;
4357  data = (char *) crumbs[i].data;
4358 
4359  /* Does data fit completely in current page ? */
4360  if ((ptr + length) >= last_ptr)
4361  while (length > 0)
4362  {
4363  if (ptr >= last_ptr)
4364  {
4365  /*
4366  * Get next page and set the current one dirty
4367  */
4369  ptr = LOG_APPEND_PTR ();
4370  last_ptr = LOG_LAST_APPEND_PTR ();
4371  }
4372  /* Find the amount of contiguous data that can be copied */
4373  if ((ptr + length) >= last_ptr)
4374  {
4375  copy_length = CAST_BUFLEN (last_ptr - ptr);
4376  }
4377  else
4378  {
4379  copy_length = length;
4380  }
4381  memcpy (ptr, data, copy_length);
4382  ptr += copy_length;
4383  data += copy_length;
4384  length -= copy_length;
4385  log_Gl.hdr.append_lsa.offset += copy_length;
4386  }
4387  else
4388  {
4389  memcpy (ptr, data, length);
4390  ptr += length;
4391  log_Gl.hdr.append_lsa.offset += length;
4392  }
4393  }
4394 
4395  /*
4396  * Align the data for future appends.
4397  * Indicate that modifications were done
4398  */
4399  LOG_APPEND_ALIGN (thread_p, LOG_SET_DIRTY);
4400 }
4401 
4402 /*
4403  * logpb_end_append - Finish appending a log record
4404  *
4405  * return: nothing
4406  *
4407  * flush(in): Is it a requirement to flush the log ?
4408  * force_flush(in):
4409  *
4410  * NOTE: Finish appending a log record. If the log record was appended
4411  * in several log buffers, these buffers are flushed and freed.
4412  * Only one append buffer will remain pin (fetched) in memory.
4413  * If the log record was appended in only one buffer, the buffer
4414  * is not flushed unless the caller requested flushing (e.g.,
4415  * for a log_commit record).
4416  */
4417 static void
4419 {
4420  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
4421 
4424 
4425  /*
4426  * Find the log_rec portion of the append record, it may not be in the
4427  * current append buffer since it can be stored in several buffers. Then,
4428  * make the log_rec point to next future append record, unless it is
4429  * the special record type used for archives created during backups
4430  * that cannot have a forward lsa and must waste the remaining space
4431  * on the current page.
4432  */
4433  assert (LSA_EQ (&header->forw_lsa, &log_Gl.hdr.append_lsa));
4434 
4436  {
4437  logpb_set_dirty (thread_p, log_Gl.append.log_pgptr);
4438  }
4439 
4441  {
4442  /* success, fall through */
4443  }
4445  {
4446  /* we need to flush the correct version now */
4448  logpb_flush_all_append_pages (thread_p);
4450  }
4451  else
4452  {
4453  /* invalid state */
4454  assert_release (false);
4455  }
4457 }
4458 
4459 /*
4460  *
4461  * FUNCTIONS RELATED TO LOG INFORMATION FILE
4462  *
4463  */
4464 
4465 /*
4466  * logpb_create_log_info - Create a log information file
4467  *
4468  * return: nothing
4469  *
4470  * logname_info(in): Name of the log information file
4471  * db_fullname(in): Name of the database or NULL (defualt to current one)
4472  *
4473  * NOTE: Creates a log information file. This file is used as a help
4474  * for the DBA of what things has been archived and what archive
4475  * logs are not needed during normal restart recovery (i.e.,
4476  * other than media crash).
4477  */
4478 void
4479 logpb_create_log_info (const char *logname_info, const char *db_fullname)
4480 {
4481  FILE *fp; /* Pointer to file */
4482  const char *catmsg;
4483  const char *db_name = db_fullname;
4484  int error_code = NO_ERROR;
4485 
4486  /* Create the information file */
4487  fp = fopen (logname_info, "w");
4488  if (fp != NULL)
4489  {
4490  fclose (fp);
4492  if (db_name == NULL)
4493  {
4494  db_name = log_Db_fullname;
4495  }
4496  if (catmsg == NULL)
4497  {
4498  catmsg = "COMMENT: %s for database %s\n";
4499  }
4500  error_code = log_dump_log_info (logname_info, false, catmsg, CUBRID_MAGIC_LOG_INFO, db_name);
4501  if (error_code != NO_ERROR)
4502  {
4503  return;
4504  }
4505 
4506  (void) logpb_add_volume (db_fullname, LOG_DBLOG_INFO_VOLID, logname_info, DISK_UNKNOWN_PURPOSE);
4507  }
4508 }
4509 
4510 
4511 /*
4512  * logpb_get_guess_archive_num - Guess archive number
4513  *
4514  * return: arvnum or -1
4515  *
4516  * pageid(in): Desired page
4517  *
4518  * NOTE: Guess the archive number where the desired page is archived by searching the log information file.
4519  */
4520 static int
4522 {
4523  FILE *fp;
4524  char line[LOG_MAX_LOGINFO_LINE];
4525  int arv_num = -1;
4526  int last_arvnum = -1;
4527  int next_arvnum;
4528  bool isfound = false;
4529  LOG_PAGEID from_pageid;
4530  LOG_PAGEID to_pageid;
4531  long long int f, t;
4532 
4533  assert (LOG_CS_OWN (thread_p));
4534 
4535  arv_num = logpb_get_archive_num_from_info_table (thread_p, pageid);
4536 
4537  if (arv_num >= 0)
4538  {
4539  return arv_num;
4540  }
4541 
4542  /*
4543  * Guess by looking into the log information file. This is just a guess
4544  */
4545  fp = fopen (log_Name_info, "r");
4546  if (fp != NULL)
4547  {
4548  while (fgets (line, LOG_MAX_LOGINFO_LINE, fp) != NULL)
4549  {
4550  if (strstr (line + TIME_SIZE_OF_DUMP_LOG_INFO,
4552  == line + TIME_SIZE_OF_DUMP_LOG_INFO)
4553  {
4554  /* A candidate for a guess */
4555  if (sscanf (line + TIME_SIZE_OF_DUMP_LOG_INFO, "%*s %d %*s %lld %lld", &next_arvnum, &f, &t) == 3)
4556  {
4557  from_pageid = f;
4558  to_pageid = t;
4559 
4560  last_arvnum = next_arvnum;
4561 
4562  if (pageid < from_pageid)
4563  {
4564  /*
4565  * keep looking.
4566  * There is likely a hole in the archive process due to media
4567  * crashes off or the log information contains some missing
4568  * entries.
4569  */
4570  continue;
4571  }
4572 
4573  arv_num = next_arvnum;
4574 
4575  if (pageid >= from_pageid && pageid <= to_pageid)
4576  {
4577  /* Found the page in this archive */
4578  isfound = true;
4579  break;
4580  }
4581  }
4582  }
4583  }
4584  fclose (fp);
4585  }
4586 
4587  if (arv_num == -1)
4588  {
4589  /*
4590  * If I have a log active, use it to find out a better archive number
4591  * for initial search
4592  */
4593  if (log_Gl.append.vdes != NULL_VOLDES)
4594  {
4595  arv_num = (int) (pageid / LOGPB_ACTIVE_NPAGES);
4596  }
4597  else
4598  {
4599  /*
4600  * We do not have a clue what it is available. Don't have log active
4601  * and likely we did not have backups.
4602  * Must trace for available archive volumes
4603  */
4604  arv_num = 0;
4605  }
4606  }
4607  else if (isfound == false && last_arvnum == arv_num && log_Gl.append.vdes != NULL_VOLDES)
4608  {
4609  /*
4610  * The log archive was chopped somehow.
4611  */
4612  arv_num = log_Gl.hdr.nxarv_num - 1;
4613  }
4614 
4615  /* Insure that we never pick one larger than the next one to be created */
4616  if (arv_num >= log_Gl.hdr.nxarv_num)
4617  {
4618  arv_num = log_Gl.hdr.nxarv_num - 1;
4619  }
4620 
4621  return arv_num;
4622 }
4623 
4624 /*
4625  * logpb_find_volume_info_exist - Find if volume information exists ?
4626  *
4627  * return:
4628  *
4629  * NOTE: Find if volume information exist.
4630  */
4631 bool
4633 {
4635 }
4636 
4637 /*
4638  * logpb_create_volume_info - Create the volume information and add first volume
4639  *
4640  * return: NO_ERROR or error code
4641  *
4642  * db_fullname(in): Name of the database or NULL (defualt to current one)
4643  *
4644  * NOTE: Create the volume information and add the first volume.
4645  */
4646 int
4647 logpb_create_volume_info (const char *db_fullname)
4648 {
4649  char vol_fullname[PATH_MAX];
4650  char *volinfo_fullname;
4651  FILE *volinfo_fp = NULL;
4652 
4653  if (db_fullname != NULL)
4654  {
4655  fileio_make_volume_info_name (vol_fullname, db_fullname);
4656  volinfo_fullname = vol_fullname;
4657  }
4658  else
4659  {
4660  volinfo_fullname = log_Name_volinfo;
4661  }
4662 
4663  volinfo_fp = fopen (volinfo_fullname, "w");
4664  if (volinfo_fp == NULL)
4665  {
4666  /* Unable to create the database volume information */
4667  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_CREATE_VOL, 2, volinfo_fullname, db_fullname);
4668  return ER_BO_CANNOT_CREATE_VOL;
4669  }
4670  /*
4671  * Write information about:
4672  * the active log and the first volume of the database
4673  * in the volume information file
4674  */
4675  fprintf (volinfo_fp, "%4d %s\n", LOG_DBVOLINFO_VOLID, volinfo_fullname);
4676 
4677  fflush (volinfo_fp);
4678  fclose (volinfo_fp);
4679 
4680  return NO_ERROR;
4681 }
4682 
4683 /*
4684  * logpb_recreate_volume_info - Recreate the database volume information
4685  *
4686  * return: NO_ERROR if all OK, ER_ status otherwise
4687  *
4688  * NOTE: Recreate the database volume information from the internal information that is stored in each volume.
4689  */
4690 int
4692 {
4693  VOLID volid = LOG_DBFIRST_VOLID; /* Current volume identifier */
4694  VOLID next_volid = LOG_DBFIRST_VOLID; /* Next volume identifier */
4695  char next_vol_fullname[PATH_MAX]; /* Next volume name */
4696  int error_code = NO_ERROR;
4697 
4698  error_code = logpb_create_volume_info (NULL);
4699  if (error_code != NO_ERROR)
4700  {
4701  goto error;
4702  }
4704  {
4705  error_code = ER_FAILED;
4706  goto error;
4707  }
4710  {
4711  error_code = ER_FAILED;
4712  goto error;
4713  }
4715  {
4716  error_code = ER_FAILED;
4717  goto error;
4718  }
4719 
4720  /* First the primary volume, then the rest of the volumes */
4721 
4722  strcpy (next_vol_fullname, log_Db_fullname);
4723 
4724  do
4725  {
4726  if (logpb_add_volume (NULL, volid, next_vol_fullname, DB_PERMANENT_DATA_PURPOSE) != volid)
4727  {
4728  error_code = ER_FAILED;
4729  goto error;
4730  }
4731 
4732  if (disk_get_link (thread_p, volid, &next_volid, next_vol_fullname) == NULL)
4733  {
4734  error_code = ER_FAILED;
4735  goto error;
4736  }
4737 
4738  volid = next_volid;
4739  }
4740  while (volid != NULL_VOLID);
4741 
4742  return error_code;
4743 
4744  /* ****** */
4745 error:
4746  (void) remove (log_Name_volinfo);
4747  return error_code;
4748 }
4749 
4750 /*
4751  * logpb_add_volume - Add a new volume entry to the volume information
4752  *
4753  * return: new_volid or NULL_VOLID
4754  *
4755  * db_fullname(in):
4756  * new_volid(in): New volume identifier
4757  * new_volfullname(in): New volume name
4758  * new_volpurpose(in): Purpose of new volume
4759  *
4760  * NOTE: Add a new entry to the volume information
4761  */
4762 /* todo: remove purpose */
4763 VOLID
4764 logpb_add_volume (const char *db_fullname, VOLID new_volid, const char *new_volfullname, DISK_VOLPURPOSE new_volpurpose)
4765 {
4766  if (new_volpurpose != DB_TEMPORARY_DATA_PURPOSE)
4767  {
4768  char vol_fullname[PATH_MAX];
4769  char *volinfo_fullname;
4770  FILE *volinfo_fp = NULL;
4771 
4772  if (db_fullname != NULL)
4773  {
4774  fileio_make_volume_info_name (vol_fullname, db_fullname);
4775  volinfo_fullname = vol_fullname;
4776  }
4777  else
4778  {
4779  volinfo_fullname = log_Name_volinfo;
4780  }
4781 
4782  volinfo_fp = fopen (volinfo_fullname, "a");
4783  if (volinfo_fp != NULL)
4784  {
4785  /* Write information about this volume in the volume information file */
4786  fprintf (volinfo_fp, "%4d %s\n", new_volid, new_volfullname);
4787  fflush (volinfo_fp);
4788  fclose (volinfo_fp);
4789 
4790  return new_volid;
4791  }
4792  else
4793  {
4794  return NULL_VOLID;
4795  }
4796  }
4797 
4798  return new_volid;
4799 }
4800 
4801 /*
4802  * logpb_scan_volume_info - Scan the volume information entries
4803  *
4804  * return: number of entries or -1 in case of error.
4805  *
4806  * db_fullname(in):
4807  * ignore_volid(in): Don't call function with this volume
4808  * start_volid(in): Scan should start at this point.
4809  * fun(in): Function to be called on each entry
4810  * args(in): Additional arguments to be passed to function
4811  *
4812  * NOTE: Scan the volume information entries calling the given function on each entry.
4813  */
4814 int
4815 logpb_scan_volume_info (THREAD_ENTRY * thread_p, const char *db_fullname, VOLID ignore_volid, VOLID start_volid,
4816  int (*fun) (THREAD_ENTRY * thread_p, VOLID xvolid, const char *vlabel, void *args), void *args)
4817 {
4818  char xxvolinfo_fullname[PATH_MAX];
4819  char *volinfo_fullname;
4820  FILE *volinfo_fp = NULL; /* Pointer to new volinfo */
4821  char vol_fullname[PATH_MAX]; /* Next volume name */
4822  VOLID volid = LOG_DBFIRST_VOLID - 1; /* Next volume identifier */
4823  int read_int_volid;
4824  VOLID num_vols = 0;
4825  bool start_scan = false;
4826  char format_string[64];
4827 
4828  if (db_fullname != NULL)
4829  {
4830  fileio_make_volume_info_name (xxvolinfo_fullname, db_fullname);
4831  volinfo_fullname = xxvolinfo_fullname;
4832  }
4833  else
4834  {
4835  volinfo_fullname = log_Name_volinfo;
4836  }
4837 
4838  volinfo_fp = fopen (volinfo_fullname, "r");
4839  if (volinfo_fp == NULL)
4840  {
4842  return -1;
4843  }
4844 
4845  sprintf (format_string, "%%d %%%ds", PATH_MAX - 1);
4846  while (true)
4847  {
4848  if (fscanf (volinfo_fp, format_string, &read_int_volid, vol_fullname) != 2)
4849  {
4850  break;
4851  }
4852 
4853  if ((volid + 1) != NULL_VOLID && (volid + 1) > (VOLID) read_int_volid && num_vols != 0)
4854  {
4855  er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_BO_UNSORTED_VOLINFO, 4, volinfo_fullname, num_vols,
4856  read_int_volid, vol_fullname);
4857  num_vols = -1;
4858  break;
4859  }
4860  volid = (VOLID) read_int_volid;
4861 
4862  if (volid == NULL_VOLID)
4863  {
4864  continue;
4865  }
4866 
4867  if (start_scan == false)
4868  {
4869  if (start_volid == read_int_volid)
4870  {
4871  start_scan = true;
4872  }
4873  else
4874  {
4875  continue;
4876  }
4877  }
4878 
4879  if (volid != ignore_volid)
4880  {
4881  if (((*fun) (thread_p, volid, vol_fullname, args)) != NO_ERROR)
4882  {
4883  num_vols = -1;
4884  break;
4885  }
4886 
4887  num_vols++;
4888  }
4889  }
4890 
4891  fclose (volinfo_fp);
4892 
4893  return num_vols;
4894 }
4895 
4896 /*
4897  *
4898  * FUNCTIONS RELATED TO LOG ARCHIVES
4899  *
4900  */
4901 
4902 /*
4903  * logpb_to_physical_pageid - Find physical page identifier of given logic page
4904  *
4905  * return: phy page identifier
4906  *
4907  * logical_pageid(in): logical_pageid: Logical log page
4908  *
4909  * NOTE: Returns the physical page identifier associated with given logical page.
4910  */
4913 {
4915 
4916  if (logical_pageid == LOGPB_HEADER_PAGE_ID)
4917  {
4918  phy_pageid = LOGPB_PHYSICAL_HEADER_PAGE_ID;
4919  }
4920  else
4921  {
4922  LOG_PAGEID tmp_pageid;
4923 
4924  tmp_pageid = logical_pageid - LOGPB_FIRST_ACTIVE_PAGE_ID;
4925  if (tmp_pageid >= LOGPB_ACTIVE_NPAGES)
4926  {
4927  tmp_pageid %= LOGPB_ACTIVE_NPAGES;
4928  }
4929  else if (tmp_pageid < 0)
4930  {
4931  tmp_pageid = LOGPB_ACTIVE_NPAGES - ((-tmp_pageid) % LOGPB_ACTIVE_NPAGES);
4932  }
4933 
4934  tmp_pageid++;
4935  if (tmp_pageid > LOGPB_ACTIVE_NPAGES)
4936  {
4937  tmp_pageid %= LOGPB_ACTIVE_NPAGES;
4938  }
4939 
4940  assert (tmp_pageid <= PAGEID_MAX);
4941  phy_pageid = (LOG_PHY_PAGEID) tmp_pageid;
4942  }
4943 
4944  return phy_pageid;
4945 }
4946 
4947 /*
4948  * logpb_is_page_in_archive - Is the given page an archive page ?
4949  *
4950  * return:
4951  *
4952  * pageid(in): Log page identifier
4953  *
4954  * NOTE:Find if given page is an archive page identifier.
4955  */
4956 bool
4958 {
4959  return LOGPB_IS_ARCHIVE_PAGE (pageid);
4960 }
4961 
4962 /*
4963  * logpb_is_smallest_lsa_in_archive - IS THE SMALLEST ACTIVE OF THE LOG ARCHIVE ?
4964  *
4965  * return:
4966  *
4967  * NOTE: Returns true if the smallest active LSA is located in an archive log.
4968  */
4969 bool
4971 {
4972  LOG_LSA lsa; /* smallest lsa */
4973 
4974  logtb_find_smallest_lsa (thread_p, &lsa);
4975  return (!LSA_ISNULL (&lsa) && logpb_is_page_in_archive (lsa.pageid));
4976 }
4977 
4978 /*
4979  * logpb_get_archive_number - Archive location of given page
4980  *
4981  * return: archive number
4982  *
4983  * pageid(in): The desired logical page
4984  *
4985  * NOTE: Find in what archive the page is located or in what archive the page should have been located.
4986  */
4987 int
4989 {
4990  int arv_num = 0;
4991 
4992  if (logpb_fetch_from_archive (thread_p, pageid, NULL, &arv_num, NULL, false) == NULL)
4993  {
4994  return -1;
4995  }
4996 
4997  if (arv_num < 0)
4998  {
4999  arv_num = 0;
5000  }
5001 
5002  return arv_num;
5003 }
5004 
5005 /*
5006  * logpb_set_unavailable_archive - Cache that given archive is unavailable
5007  *
5008  * return: nothing
5009  *
5010  * arv_num(in): Log archive number
5011  *
5012  * NOTE: Record that give archive is unavialble.
5013  */
5014 static void
5016 {
5017  int *ptr;
5018  int size;
5019 
5021 
5023  {
5024  size = sizeof (*log_Gl.archive.unav_archives) * 10;
5025  ptr = (int *) malloc (size);
5026  if (ptr == NULL)
5027  {
5028  return;
5029  }
5030  log_Gl.archive.max_unav = 10;
5031  log_Gl.archive.next_unav = 0;
5033  }
5034  else
5035  {
5037  {
5038  size = (sizeof (*log_Gl.archive.unav_archives) * (log_Gl.archive.max_unav + 10));
5039  ptr = (int *) realloc (log_Gl.archive.unav_archives, size);
5040  if (ptr == NULL)
5041  {
5042  return;
5043  }
5044  log_Gl.archive.max_unav += 10;
5046  }
5047  }
5048 
5050 }
5051 
5052 /*
5053  * logpb_dismount_log_archive - dismount archive log
5054  *
5055  * return: nothing
5056  *
5057  * It dismounts and resets log_Gl.archive.vdes
5058  */
5059 static void
5061 {
5062  LOG_ARCHIVE_CS_ENTER (thread_p);
5063 
5064  if (log_Gl.archive.vdes != NULL_VOLDES)
5065  {
5066  fileio_dismount (thread_p, log_Gl.archive.vdes);
5068  }
5069 
5070  LOG_ARCHIVE_CS_EXIT (thread_p);
5071 }
5072 
5073 /*
5074  * logpb_decache_archive_info - Decache any archive log memory information
5075  *
5076  * return: nothing
5077  *
5078  * NOTE: Decache any archive log memory information.
5079  */
5080 void
5082 {
5083  LOG_ARCHIVE_CS_ENTER (thread_p);
5084 
5085  if (log_Gl.archive.vdes != NULL_VOLDES)
5086  {
5087  logpb_dismount_log_archive (thread_p);
5088  }
5089 
5091  {
5093  log_Gl.archive.max_unav = 0;
5094  log_Gl.archive.next_unav = 0;
5095  }
5096 
5097  LOG_ARCHIVE_CS_EXIT (thread_p);
5098 }
5099 
5100 /*
5101  * log_isarchive_available - Is given archive available ?
5102  *
5103  * return: true/false
5104  * true: means that the archive may be available.
5105  * false: it is known that archive is not available.
5106  *
5107  * arv_num(in): Log archive number
5108  *
5109  * NOTE:Find if the current archive is available.
5110  */
5111 static bool
5112 logpb_is_archive_available (THREAD_ENTRY * thread_p, int arv_num)
5113 {
5114  int i;
5115 
5116  assert (LOG_CS_OWN (thread_p));
5118 
5119  if (arv_num >= log_Gl.hdr.nxarv_num || arv_num < 0)
5120  {
5121  return false;
5122  }
5123 
5125  {
5126  for (i = 0; i < log_Gl.archive.next_unav; i++)
5127  {
5128  if (log_Gl.archive.unav_archives[i] == arv_num)
5129  {
5130  return false;
5131  }
5132  }
5133  }
5134 
5135  return true;
5136 }
5137 
5138 /*
5139  * log_fetch_from_archive - Fetch a log page from the log archives
5140  *
5141  * return: log_pgptr or NULL (in case of error)
5142  *
5143  * pageid(in): The desired logical page
5144  * log_pgptr(in): Place to return the log page
5145  * arv_num(in): Set to archive number where page was found or where page
5146  * should have been found.
5147  *
5148  * NOTE: Fetch a log page from archive logs.
5149  */
5150 LOG_PAGE *
5152  int *ret_arv_num, LOG_ARV_HEADER * ret_arv_hdr, bool is_fatal)
5153 {
5154  char hdr_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_hdr_pgbuf;
5155  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
5156  LOG_ARV_HEADER *arv_hdr;
5157  LOG_PAGE *hdr_pgptr;
5159  char arv_name[PATH_MAX];
5160  const char *tmp_arv_name;
5161  int arv_num, vdes;
5162  int direction = 0, retry;
5163  bool has_guess_arvnum = false, first_time = true;
5164  int error_code = NO_ERROR;
5165  char format_string[64];
5166 
5167  assert (LOG_CS_OWN (thread_p));
5168 
5169  logpb_log ("called logpb_fetch_from_archive for pageid = %lld\n", (long long int) pageid);
5170 
5171  LOG_ARCHIVE_CS_ENTER (thread_p);
5172 
5173  aligned_hdr_pgbuf = PTR_ALIGN (hdr_pgbuf, MAX_ALIGNMENT);
5174  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
5175 
5176 #if !defined(NDEBUG)
5178  {
5179  fprintf (stdout, "\n **log_fetch_from_archive has been called on pageid = %lld ** \n", (long long int) pageid);
5180  fflush (stdout);
5181  }
5182 #endif
5183 
5184  hdr_pgptr = (LOG_PAGE *) aligned_hdr_pgbuf;
5185  if (log_pgptr == NULL)
5186  {
5187  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
5188  }
5189  if (ret_arv_num == NULL)
5190  {
5191  ret_arv_num = &arv_num;
5192  }
5193 
5194  if (log_Gl.archive.vdes == NULL_VOLDES)
5195  {
5196  if (log_Gl.hdr.nxarv_num <= 0)
5197  {
5198  /* We do not have any archives */
5200 
5201  LOG_ARCHIVE_CS_EXIT (thread_p);
5202  return NULL;
5203  }
5204 
5205  /*
5206  * Guess the archive where that page is stored
5207  */
5208 
5209  has_guess_arvnum = true;
5210  *ret_arv_num = logpb_get_guess_archive_num (thread_p, pageid);
5211  fileio_make_log_archive_name (arv_name, log_Archive_path, log_Prefix, *ret_arv_num);
5212 
5213  error_code = ER_FAILED;
5214  if (logpb_is_archive_available (thread_p, *ret_arv_num) == true && fileio_is_volume_exist (arv_name) == true)
5215  {
5216  vdes = fileio_mount (thread_p, log_Db_fullname, arv_name, LOG_DBLOG_ARCHIVE_VOLID, false, false);
5217  if (vdes != NULL_VOLDES)
5218  {
5219  if (fileio_read (thread_p, vdes, hdr_pgptr, 0, LOG_PAGESIZE) == NULL)
5220  {
5221  fileio_dismount (thread_p, vdes);
5222  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_READ, 3, 0LL, 0LL, arv_name);
5223 
5224  LOG_ARCHIVE_CS_EXIT (thread_p);
5225  return NULL;
5226  }
5227  error_code = NO_ERROR;
5228  arv_hdr = (LOG_ARV_HEADER *) hdr_pgptr->area;
5230  {
5231  if (difftime64 ((time_t) arv_hdr->db_creation, (time_t) log_Gl.hdr.db_creation) != 0)
5232  {
5233  /*
5234  * This volume does not belong to the database. For now, assume
5235  * that it is not only. Later, we will give this error to user
5236  */
5237  vdes = NULL_VOLDES;
5238  arv_hdr = NULL;
5239  }
5240  }
5241  }
5242  }
5243 
5244  if (error_code != NO_ERROR)
5245  {
5246  /*
5247  * The volume is not online. Ask for it later (below). But first try to
5248  * make the best guess for the archive number.
5249  */
5250  vdes = NULL_VOLDES;
5251  arv_hdr = NULL;
5252  }
5253  }
5254  else
5255  {
5256  vdes = log_Gl.archive.vdes;
5257  arv_hdr = &log_Gl.archive.hdr;
5258  *ret_arv_num = arv_hdr->arv_num;
5259  }
5260 
5261  sprintf (format_string, "%%%ds", PATH_MAX - 1);
5262 
5264  while (true)
5265  {
5266  /* Is the page in current archive log ? */
5267  if (arv_hdr != NULL && pageid >= arv_hdr->fpageid && pageid <= arv_hdr->fpageid + arv_hdr->npages - 1)
5268  {
5269  /* Find location of logical page in the archive log */
5270  phy_pageid = (LOG_PHY_PAGEID) (pageid - arv_hdr->fpageid + 1);
5271 
5272  /* Record number of reads in statistics */
5274 
5275  if (fileio_read (thread_p, vdes, log_pgptr, phy_pageid, LOG_PAGESIZE) == NULL)
5276  {
5277  /* Error reading archive page */
5278  tmp_arv_name = fileio_get_volume_label_by_fd (vdes, PEEK);
5279  fileio_dismount (thread_p, vdes);
5281  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_READ, 3, pageid, phy_pageid, tmp_arv_name);
5282 
5283  LOG_ARCHIVE_CS_EXIT (thread_p);
5284  return NULL;
5285  }
5286 
5287  TDE_ALGORITHM tde_algo = logpb_get_tde_algorithm (log_pgptr);
5288  if (tde_algo != TDE_ALGORITHM_NONE)
5289  {
5290  if (tde_decrypt_log_page (log_pgptr, tde_algo, log_pgptr) != NO_ERROR)
5291  {
5292  ASSERT_ERROR ();
5293  LOG_ARCHIVE_CS_EXIT (thread_p);
5294  return NULL;
5295  }
5296  }
5297 
5298  /* Cast the archive information. May be used again */
5299  if (arv_hdr != &log_Gl.archive.hdr)
5300  {
5301  log_Gl.archive.hdr = *arv_hdr;
5302  }
5303  log_Gl.archive.vdes = vdes;
5304  break;
5305  }
5306  else
5307  {
5308  /* If any archive dismount it */
5309  if (vdes != NULL_VOLDES)
5310  {
5311  fileio_dismount (thread_p, vdes);
5312  vdes = NULL_VOLDES;
5313  }
5314 
5315  if (has_guess_arvnum == false)
5316  {
5317  has_guess_arvnum = true;
5318  retry = logpb_get_guess_archive_num (thread_p, pageid);
5319  if (retry != *ret_arv_num)
5320  {
5321  *ret_arv_num = retry;
5322  }
5323  }
5324  else
5325  {
5326  if (direction == 0)
5327  {
5328  /*
5329  * Define the direction by looking for desired page
5330  */
5331  if (arv_hdr != NULL)
5332  {
5333  if (pageid < arv_hdr->fpageid)
5334  {
5335  /* Try older archives */
5336  direction = -1;
5337  }
5338  else
5339  {
5340  /* Try newer archives */
5341  direction = 1;
5342  }
5343  }
5344  else
5345  {
5346  if (first_time != true)
5347  {
5348  if (log_Gl.append.vdes == NULL_VOLDES)
5349  {
5350  direction = 1;
5351  }
5352  else
5353  {
5354  /*
5355  * Start looking from the last archive.
5356  * Optimized for UNDO.. This is not so bad since this branch
5357  * will be reached only when the guess archive is not
5358  * available.
5359  */
5360  *ret_arv_num = log_Gl.hdr.nxarv_num;
5361  direction = -1;
5362  }
5363  }
5364  }
5365  }
5366 
5367  if (arv_hdr != NULL)
5368  {
5369  if (direction == -1)
5370  {
5371  /*
5372  * Try an older archive.
5373  * The page that I am looking MUST be smaller than the first
5374  * page in current archive
5375  */
5376  if (pageid < arv_hdr->fpageid)
5377  {
5378  *ret_arv_num -= 1;
5379  }
5380  else
5381  {
5382  *ret_arv_num = -1;
5383  }
5384  }
5385  else
5386  {
5387  /* Try a newer archive. The page that I am looking MUST be larger than the last page in current
5388  * archive */
5389  if (pageid > arv_hdr->fpageid + arv_hdr->npages - 1)
5390  {
5391  *ret_arv_num += 1;
5392  }
5393  else
5394  {
5395  *ret_arv_num = log_Gl.hdr.nxarv_num;
5396  }
5397  }
5398  }
5399  else
5400  {
5401  /*
5402  * The archive number is not increased the first time in the loop,
5403  * so we can ask for it when it is not available.
5404  */
5405  if (first_time != true)
5406  {
5407  /*
5408  * If we do not have the log active, we don't really know how to
5409  * continue, we could be looping forever.
5410  */
5411  if (log_Gl.append.vdes == NULL_VOLDES)
5412  {
5413  *ret_arv_num = -1;
5414  }
5415  else
5416  {
5417  *ret_arv_num = *ret_arv_num + direction;
5418  }
5419  }
5420  }
5421 
5422  first_time = false;
5423  if (*ret_arv_num < 0 || *ret_arv_num == log_Gl.hdr.nxarv_num)
5424  {
5425  /* Unable to find page in archive */
5426  if (log_Gl.append.vdes != NULL_VOLDES)
5427  {
5429  }
5430  else
5431  {
5432  /*
5433  * This is likely an incomplete recovery (restore).
5434  * We do not have the active log and we are looking for a log page
5435  */
5437  }
5438 
5439  LOG_ARCHIVE_CS_EXIT (thread_p);
5440 
5441  return NULL;
5442  }
5443  }
5444 
5445  if (logpb_is_archive_available (thread_p, *ret_arv_num) == false)
5446  {
5447  arv_hdr = NULL;
5448  continue;
5449  }
5450 
5451  fileio_make_log_archive_name (arv_name, log_Archive_path, log_Prefix, *ret_arv_num);
5452  retry = 3;
5453  while (retry != 0 && retry != 1
5454  && (vdes =
5455  fileio_mount (thread_p, log_Db_fullname, arv_name, LOG_DBLOG_ARCHIVE_VOLID, false,
5456  false)) == NULL_VOLDES)
5457  {
5458  char line_buf[PATH_MAX * 2];
5459  bool is_in_crash_recovery;
5460 
5461  is_in_crash_recovery = log_is_in_crash_recovery ();
5462 
5463  /*
5464  * The archive is not online.
5465  */
5466  if (is_in_crash_recovery == true)
5467  {
5468  fprintf (stdout, "%s\n", er_msg ());
5469  }
5470 
5471  retry_prompt:
5473  {
5475  if (retry == 1 && is_in_crash_recovery == true)
5476  {
5477  fprintf (stdout, "Continue without present archive. (Partial recovery).\n");
5478  }
5479  }
5480  else
5481  {
5484  arv_name);
5486 
5487  if (fgets (line_buf, PATH_MAX, stdin) == NULL)
5488  {
5489  retry = 0; /* EOF */
5490  }
5491  else if (sscanf (line_buf, "%d", &retry) != 1)
5492  {
5493  retry = -1; /* invalid input */
5494  }
5495  }
5496 
5497  switch (retry)
5498  {
5499  case 0: /* quit */
5500  logpb_set_unavailable_archive (thread_p, *ret_arv_num);
5502  if (is_fatal)
5503  {
5504  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_fetch_from_archive");
5505  }
5506 
5507  LOG_ARCHIVE_CS_EXIT (thread_p);
5508 
5509  return NULL;
5510 
5511  case 1: /* Not available */
5512  logpb_set_unavailable_archive (thread_p, *ret_arv_num);
5513  break;
5514 
5515  case 3: /* Relocate */
5517  if (fgets (line_buf, PATH_MAX, stdin) == 0 || (sscanf (line_buf, format_string, arv_name) != 1))
5518  {
5519  fileio_make_log_archive_name (arv_name, log_Archive_path, log_Prefix, *ret_arv_num);
5520  }
5521  break;
5522 
5523  case 2: /* Retry */
5524  break;
5525 
5526  default: /* Something strange. Get user to try again. */
5528  0, 3);
5529  goto retry_prompt;
5530  }
5531  }
5532 
5533  if (vdes != NULL_VOLDES)
5534  {
5535  /* Read header page and make sure the page is here */
5536 
5537  /* Record number of reads in statistics */
5539 
5540  if (fileio_read (thread_p, vdes, hdr_pgptr, 0, LOG_PAGESIZE) == NULL)
5541  {
5542  fileio_dismount (thread_p, vdes);
5543  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_READ, 3, 0LL, 0LL, arv_name);
5544 
5545  LOG_ARCHIVE_CS_EXIT (thread_p);
5546 
5547  return NULL;
5548  }
5549  arv_hdr = (LOG_ARV_HEADER *) hdr_pgptr->area;
5551  {
5552  if (difftime64 ((time_t) arv_hdr->db_creation, (time_t) log_Gl.hdr.db_creation) != 0)
5553  {
5554  /*
5555  * This volume does not belong to the database. For now, assume
5556  * that it is not only. Later, we will give this error to user
5557  */
5559  arv_name);
5560  arv_hdr = NULL;
5561  }
5562  }
5563  }
5564  else
5565  {
5566  arv_hdr = NULL;
5567  }
5568  }
5569  }
5570 
5571 #if defined(CUBRID_DEBUG)
5572  if (log_pgptr->hdr.logical_pageid != pageid)
5573  {
5575  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_fetch_from_archive");
5576 
5577  LOG_ARCHIVE_CS_EXIT (thread_p);
5578 
5579  return NULL;
5580  }
5581 #endif /* CUBRID_DEBUG */
5582 
5583 #if !defined (NDEBUG)
5584  /* In analysys phase, the page may be corrupted. */
5586  {
5587  logpb_debug_check_log_page (thread_p, log_pgptr);
5588  }
5589 #endif /* !NDEBUG */
5590 
5591  assert (log_pgptr != NULL && *ret_arv_num != -1 && arv_hdr != NULL);
5592  if (ret_arv_hdr != NULL)
5593  {
5594  *ret_arv_hdr = *arv_hdr;
5595  }
5596 
5597  LOG_ARCHIVE_CS_EXIT (thread_p);
5598 
5599  return log_pgptr;
5600 }
5601 
5602 /*
5603  * logpb_archive_active_log - Archive the active portion of the log
5604  *
5605  * return: nothing
5606  *
5607  * NOTE: The active portion of the log is archived from the next log
5608  * archive page to the previous log page of the current append
5609  * log record, to the next log archive.
5610  */
5611 static void
5613 {
5614  char arv_name[PATH_MAX] = { '\0' }; /* Archive name */
5615  LOG_PAGE *malloc_arv_hdr_pgptr = NULL; /* Archive header page PTR */
5616  LOG_ARV_HEADER *arvhdr; /* Archive header */
5617  BACKGROUND_ARCHIVING_INFO *bg_arv_info;
5618  char log_pgbuf[IO_MAX_PAGE_SIZE * LOGPB_IO_NPAGES + MAX_ALIGNMENT];
5619  char *aligned_log_pgbuf;
5620  LOG_PAGE *log_pgptr = NULL;
5621  LOG_PAGEID pageid, last_pageid;
5622  LOG_PHY_PAGEID ar_phy_pageid;
5623  int vdes = NULL_VOLDES;
5624  const char *catmsg;
5625  int error_code = NO_ERROR;
5626  int num_pages = 0;
5627  FILEIO_WRITE_MODE write_mode;
5628 
5629  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
5630 
5631  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
5632 
5633 #if defined(SERVER_MODE)
5635 #else
5637 #endif
5638 
5639  logpb_log ("Entered logpb_archive_active_log. log_Gl.hdr.nxarv_phy_pageid = %lld , log_Gl.hdr.nxarv_pageid =%lld\n",
5640  (long long int) log_Gl.hdr.nxarv_phy_pageid, (long long int) log_Gl.hdr.nxarv_pageid);
5641 
5643  {
5645  "log_archive_active_log: WARNING Trying to archive ONLY the append page" " which is incomplete\n");
5646  return;
5647  }
5648 
5649  bg_arv_info = &log_Gl.bg_archive_info;
5650  if (log_Gl.archive.vdes != NULL_VOLDES)
5651  {
5652  /* A recheck is required after logpb_flush_all_append_pages when LOG_CS is demoted and promoted.
5653  * log_Gl.archive.vdes may be modified by someone else. Should we remove this dismount? */
5654  logpb_dismount_log_archive (thread_p);
5655  }
5656 
5657  malloc_arv_hdr_pgptr = (LOG_PAGE *) malloc (LOG_PAGESIZE);
5658  if (malloc_arv_hdr_pgptr == NULL)
5659  {
5660  goto error;
5661  }
5662  memset (malloc_arv_hdr_pgptr, LOG_PAGE_INIT_VALUE, LOG_PAGESIZE);
5663 
5664  /* Must force the log here to avoid nasty side effects */
5665  logpb_flush_all_append_pages (thread_p);
5666 
5667  malloc_arv_hdr_pgptr->hdr.logical_pageid = LOGPB_HEADER_PAGE_ID;
5668  malloc_arv_hdr_pgptr->hdr.offset = NULL_OFFSET;
5669  malloc_arv_hdr_pgptr->hdr.flags = 0; /* Now flags in header page has always 0 value */
5670 
5671  /* Construct the archive log header */
5672  arvhdr = (LOG_ARV_HEADER *) malloc_arv_hdr_pgptr->area;
5674  arvhdr->db_creation = log_Gl.hdr.db_creation;
5675  arvhdr->next_trid = log_Gl.hdr.next_trid;
5676  arvhdr->arv_num = log_Gl.hdr.nxarv_num;
5677 
5678  /*
5679  * All pages must be archived... even the ones with unactive log records
5680  * This is the desired parameter to support multimedia crashes.
5681  *
5682  *
5683  * Note that the npages field does not include the previous lsa page
5684  *
5685  */
5686  arvhdr->fpageid = log_Gl.hdr.nxarv_pageid;
5687  last_pageid = log_Gl.append.prev_lsa.pageid - 1;
5688 
5689  if (last_pageid < arvhdr->fpageid)
5690  {
5691  last_pageid = arvhdr->fpageid;
5692  }
5693 
5694  arvhdr->npages = (DKNPAGES) (last_pageid - arvhdr->fpageid + 1);
5695 
5696  /*
5697  * Now create the archive and start copying pages
5698  */
5699 
5701 
5703 
5705  {
5706  vdes = bg_arv_info->vdes;
5707  }
5708  else
5709  {
5710  vdes = fileio_format (thread_p, log_Db_fullname, arv_name, LOG_DBLOG_ARCHIVE_VOLID, arvhdr->npages + 1, false,
5711  false, false, LOG_PAGESIZE, 0, false);
5712  if (vdes == NULL_VOLDES)
5713  {
5714  /* Unable to create archive log to archive */
5716  arvhdr->fpageid + arvhdr->npages - 1);
5717  goto error;
5718  }
5719  }
5720 
5721  log_archive_er_log ("logpb_archive_active_log, arvhdr->fpageid = %lld\n", arvhdr->fpageid);
5722 
5723  error_code = logpb_set_page_checksum (thread_p, malloc_arv_hdr_pgptr);
5724  if (error_code != NO_ERROR)
5725  {
5726  goto error;
5727  }
5728 
5730  if (fileio_write (thread_p, vdes, malloc_arv_hdr_pgptr, 0, LOG_PAGESIZE, write_mode) == NULL)
5731  {
5732  /* Error archiving header page into archive */
5733  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_WRITE, 3, 0LL, 0LL, arv_name);
5734  goto error;
5735  }
5736 
5738  && arvhdr->fpageid == bg_arv_info->start_page_id)
5739  {
5740  pageid = bg_arv_info->current_page_id;
5741  ar_phy_pageid = (LOG_PHY_PAGEID) (bg_arv_info->current_page_id - bg_arv_info->start_page_id + 1);
5742  }
5743  else
5744  {
5746 
5747  pageid = arvhdr->fpageid;
5748  ar_phy_pageid = 1;
5749  }
5750 
5751  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
5752 
5753  /* Now start dumping the current active pages to archive */
5754  for (; pageid <= last_pageid; pageid += num_pages, ar_phy_pageid += num_pages)
5755  {
5756  logpb_log ("Dump page %lld in logpb_archive_active_log, num_pages = %d\n", (long long int) pageid, num_pages);
5757  num_pages = (int) MIN (LOGPB_IO_NPAGES, last_pageid - pageid + 1);
5758  num_pages = logpb_read_page_from_active_log (thread_p, pageid, num_pages, false, log_pgptr);
5759  if (num_pages <= 0)
5760  {
5761  goto error;
5762  }
5763 
5764  /* no need to encrypt, it is read as not decrypted (TDE) */
5765  if (fileio_write_pages (thread_p, vdes, (char *) log_pgptr, ar_phy_pageid, num_pages, LOG_PAGESIZE,
5767  {
5768  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_WRITE, 3, pageid, ar_phy_pageid, arv_name);
5769  goto error;
5770  }
5771  }
5772 
5774  {
5775  fileio_dismount (thread_p, vdes);
5776  vdes = NULL_VOLDES;
5777  bg_arv_info->vdes = NULL_VOLDES;
5778 
5779  /* rename _lgar_t to _lgar[number] name */
5780  if (fileio_rename (NULL_VOLID, log_Name_bg_archive, arv_name) == NULL)
5781  {
5782  goto error;
5783  }
5784 
5785  vdes = fileio_mount (thread_p, log_Db_fullname, arv_name, LOG_DBLOG_ARCHIVE_VOLID, 0, false);
5786  if (vdes == NULL_VOLDES)
5787  {
5788  goto error;
5789  }
5790  }
5791  else
5792  {
5793  /*
5794  * Make sure that the whole log archive is in physical storage at this
5795  * moment. System volume. No need to sync DWB.
5796  */
5797  if (fileio_synchronize (thread_p, vdes, arv_name, FILEIO_SYNC_ONLY) == NULL_VOLDES)
5798  {
5799  goto error;
5800  }
5801  }
5802 
5803  /* The last archive needed for system crashes */
5805  {
5807  }
5808 
5809  log_Gl.hdr.nxarv_num++;
5810  log_Gl.hdr.nxarv_pageid = last_pageid + 1;
5812 
5814 
5815  logpb_log
5816  ("In logpb_archive_active_log, new values from log_Gl.hdr.nxarv_pageid = %lld and log_Gl.hdr.nxarv_phy_pageid = %lld\n",
5817  (long long int) log_Gl.hdr.nxarv_pageid, (long long int) log_Gl.hdr.nxarv_phy_pageid);
5818  /* Flush the log header to reflect the archive */
5819  logpb_flush_header (thread_p);
5820 
5821 #if 0
5823  {
5825  }
5826 #endif
5827 
5828  er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_LOG_ARCHIVE_CREATED, 3, arv_name, arvhdr->fpageid, last_pageid);
5829 
5830  /* Cast the archive information. May be used again */
5831 
5832  LOG_ARCHIVE_CS_ENTER (thread_p);
5833 
5834  log_Gl.archive.hdr = *arvhdr; /* Copy of structure */
5835  if (log_Gl.archive.vdes != NULL_VOLDES)
5836  {
5837  logpb_dismount_log_archive (thread_p);
5838  }
5839  log_Gl.archive.vdes = vdes;
5840 
5841  LOG_ARCHIVE_CS_EXIT (thread_p);
5842 
5844  if (catmsg == NULL)
5845  {
5846  catmsg = "ARCHIVE: %d %s %lld %lld\n";
5847  }
5848  error_code =
5849  log_dump_log_info (log_Name_info, true, catmsg, log_Gl.hdr.nxarv_num - 1, arv_name, arvhdr->fpageid, last_pageid);
5850  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
5851  {
5852  goto error;
5853  }
5854 
5855  (void) logpb_add_archive_page_info (thread_p, log_Gl.hdr.nxarv_num - 1, arvhdr->fpageid, last_pageid);
5856 
5857 #if defined(SERVER_MODE)
5858  if (!HA_DISABLED ())
5859  {
5860  LOG_PAGEID min_fpageid = logwr_get_min_copied_fpageid ();
5861  if (min_fpageid != NULL_PAGEID)
5862  {
5863  int unneeded_arvnum = -1;
5864  if (min_fpageid >= arvhdr->fpageid)
5865  {
5866  unneeded_arvnum = arvhdr->arv_num - 1;
5867  }
5868  else
5869  {
5870  LOG_ARV_HEADER min_arvhdr;
5871  if (logpb_fetch_from_archive (thread_p, min_fpageid, NULL, NULL, &min_arvhdr, false) != NULL)
5872  {
5873  unneeded_arvnum = min_arvhdr.arv_num - 1;
5874  }
5875  }
5876  if (unneeded_arvnum >= 0)
5877  {
5878  char unneeded_logarv_name[PATH_MAX];
5879  fileio_make_log_archive_name (unneeded_logarv_name, log_Archive_path, log_Prefix, unneeded_arvnum);
5880 
5881  catmsg =
5883  if (catmsg == NULL)
5884  {
5885  catmsg =
5886  "29 COMMENT: Log archive %s, which contains log pages before %lld,"
5887  " is not needed any longer by any HA utilities.\n";
5888  }
5889  error_code = log_dump_log_info (log_Name_info, true, catmsg, unneeded_logarv_name, min_fpageid);
5890  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
5891  {
5892  goto error;
5893  }
5894  }
5895  }
5896  }
5897 
5898 #endif /* SERVER_MODE */
5899 
5900 
5902  {
5903  /* rename removed archive log file to reuse it */
5905 
5906  bg_arv_info->vdes =
5908  false, false, false, LOG_PAGESIZE, 0, true);
5909  if (bg_arv_info->vdes != NULL_VOLDES)
5910  {
5911  bg_arv_info->start_page_id = log_Gl.hdr.nxarv_pageid;
5912  bg_arv_info->current_page_id = log_Gl.hdr.nxarv_pageid;
5913  bg_arv_info->last_sync_pageid = log_Gl.hdr.nxarv_pageid;
5914  }
5915  else
5916  {
5917  bg_arv_info->start_page_id = NULL_PAGEID;
5918  bg_arv_info->current_page_id = NULL_PAGEID;
5919  bg_arv_info->last_sync_pageid = NULL_PAGEID;
5920 
5921  er_log_debug (ARG_FILE_LINE, "Unable to create temporary archive log %s\n", log_Name_bg_archive);
5922  }
5923  }
5924 
5925  log_archive_er_log ("logpb_archive_active_log end, arvhdr->fpageid = %lld, arvhdr->npages = %d\n", arvhdr->fpageid,
5926  arvhdr->npages);
5927 
5928  free_and_init (malloc_arv_hdr_pgptr);
5929 
5930  return;
5931 
5932  /* ********* */
5933 error:
5934 
5935  if (malloc_arv_hdr_pgptr != NULL)
5936  {
5937  free_and_init (malloc_arv_hdr_pgptr);
5938  }
5939 
5940  if (vdes != NULL_VOLDES)
5941  {
5942  fileio_dismount (thread_p, vdes);
5943  fileio_unformat (thread_p, arv_name);
5944  }
5945 
5947  {
5948  if (bg_arv_info->vdes != NULL_VOLDES && bg_arv_info->vdes != vdes)
5949  {
5950  fileio_dismount (thread_p, bg_arv_info->vdes);
5951  }
5953  bg_arv_info->vdes = NULL_VOLDES;
5954  }
5955 
5956  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_archive_active_log");
5957 }
5958 
5959 int
5961 {
5962  int first_arv_num_to_delete = -1;
5963  int last_arv_num_to_delete = -1;
5964  int min_arv_required_for_vacuum;
5965  LOG_PAGEID vacuum_first_pageid = NULL_PAGEID;
5966 #if defined(SERVER_MODE)
5967  LOG_PAGEID min_copied_pageid;
5968  int min_copied_arv_num;
5969 #endif /* SERVER_MODE */
5970  int num_remove_arv_num;
5971  int log_max_archives = prm_get_integer_value (PRM_ID_LOG_MAX_ARCHIVES);
5972  char *catmsg;
5973  int deleted_count = 0;
5974 
5975  if (log_max_archives == INT_MAX)
5976  {
5977  return 0; /* none is deleted */
5978  }
5979 
5981  {
5982  /* we don't know yet what is the first log page required by vacuum so it is not safe to remove log archives.
5983  unfortunately, to update the oldest vacuum data log pageid can be done only after loading vacuum data from
5984  disk, which in turn can only happen after recovery. this will block any log archive removal until vacuum
5985  is loaded. */
5986  return 0;
5987  }
5988 
5989  /* Get first log pageid needed for vacuum before locking LOG_CS. */
5990  vacuum_first_pageid = vacuum_min_log_pageid_to_keep (thread_p);
5991 
5992  LOG_CS_ENTER (thread_p);
5993 
5995  {
5996 #if defined(SERVER_MODE)
5997  min_copied_pageid = logwr_get_min_copied_fpageid ();
5998  if (min_copied_pageid == NULL_PAGEID)
5999  {
6000  LOG_CS_EXIT (thread_p);
6001  return 0; /* none is deleted */
6002  }
6003 
6004  if (logpb_is_page_in_archive (min_copied_pageid))
6005  {
6006  min_copied_arv_num = logpb_get_archive_number (thread_p, min_copied_pageid);
6007  if (min_copied_arv_num == -1)
6008  {
6009  LOG_CS_EXIT (thread_p);
6010  return 0; /* none is deleted */
6011  }
6012  else if (min_copied_arv_num > 1)
6013  {
6014  min_copied_arv_num--;
6015  }
6016 
6017  num_remove_arv_num = MAX (log_max_archives, log_Gl.hdr.nxarv_num - min_copied_arv_num);
6018  }
6019  else
6020  {
6021  num_remove_arv_num = log_max_archives;
6022  }
6023 #else /* SERVER_MODE */
6024  num_remove_arv_num = log_max_archives;
6025 #endif
6026  }
6027  else
6028  {
6029  num_remove_arv_num = log_max_archives;
6030  }
6031 
6032  if ((log_Gl.hdr.nxarv_num - (log_Gl.hdr.last_deleted_arv_num + 1)) > num_remove_arv_num)
6033  {
6035 
6036  /* Remove the log archives at this point */
6037  first_arv_num_to_delete = log_Gl.hdr.last_deleted_arv_num + 1;
6038  last_arv_num_to_delete = log_Gl.hdr.nxarv_num - num_remove_arv_num;
6039 
6041  {
6042  last_arv_num_to_delete = MIN (last_arv_num_to_delete, log_Gl.hdr.last_arv_num_for_syscrashes);
6043  }
6044  vacuum_er_log (VACUUM_ER_LOG_ARCHIVES, "First log pageid in vacuum data is %lld", vacuum_first_pageid);
6045  if (vacuum_first_pageid != NULL_PAGEID && logpb_is_page_in_archive (vacuum_first_pageid))
6046  {
6047  min_arv_required_for_vacuum = logpb_get_archive_number (thread_p, vacuum_first_pageid);
6048  vacuum_er_log (VACUUM_ER_LOG_ARCHIVES, "First archive number used for vacuum is %d",
6049  min_arv_required_for_vacuum);
6050  if (min_arv_required_for_vacuum >= 0)
6051  {
6052  last_arv_num_to_delete = MIN (last_arv_num_to_delete, min_arv_required_for_vacuum);
6053  }
6054  else
6055  {
6056  /* Page should be in archive. */
6057  assert (false);
6058  }
6059  }
6060 
6061  if (max_count > 0)
6062  {
6063  /* check max count for deletion */
6064  last_arv_num_to_delete = MIN (last_arv_num_to_delete, first_arv_num_to_delete + max_count);
6065  }
6066 
6067  last_arv_num_to_delete--;
6068  if (last_arv_num_to_delete >= first_arv_num_to_delete)
6069  {
6070  log_Gl.hdr.last_deleted_arv_num = last_arv_num_to_delete;
6071 
6072 #if defined (SA_MODE)
6074  {
6075  /* Update the last_blockid needed for vacuum. Get the first page_id of the previously logged archive */
6077  }
6078 #endif /* SA_MODE */
6079  logpb_flush_header (thread_p); /* to get rid of archives */
6080  }
6081 
6082  vacuum_er_log (VACUUM_ER_LOG_ARCHIVES, "last_arv_num_to_delete is %d", last_arv_num_to_delete);
6083  }
6084 
6085  LOG_CS_EXIT (thread_p);
6086 
6087  if (last_arv_num_to_delete >= 0 && last_arv_num_to_delete >= first_arv_num_to_delete)
6088  {
6090  {
6091  /* this is too problematic not to log in server error log too! */
6092  _er_log_debug (ARG_FILE_LINE, "Purge archives starting with %d and up until %d; "
6093  "vacuum_first_pageid = %d, last_arv_num_for_syscrashes = %d",
6094  first_arv_num_to_delete, last_arv_num_to_delete, vacuum_first_pageid,
6096  }
6097 
6099  if (catmsg == NULL)
6100  {
6101  catmsg = (char *) "Number of active log archives has been exceeded the max desired number.";
6102  }
6103  deleted_count =
6104  logpb_remove_archive_logs_internal (thread_p, first_arv_num_to_delete, last_arv_num_to_delete, catmsg);
6105  }
6106 
6107  return deleted_count;
6108 }
6109 
6110 /*
6111  * logpb_remove_archive_logs - Remove all unactive log archives
6112  *
6113  * return: nothing
6114  *
6115  * info_reason(in):
6116  *
6117  * NOTE: Archive that are not needed for system crashes and vacuum are removed.
6118  * That these archives may be needed for media crash recovery.
6119  * Therefore, it is important that the user copy these archives
6120  * to tape. Check the log information file.
6121  */
6122 void
6123 logpb_remove_archive_logs (THREAD_ENTRY * thread_p, const char *info_reason)
6124 {
6125 #if !defined(SERVER_MODE)
6126  LOG_LSA flush_upto_lsa; /* Flush data pages up to LSA */
6127 #endif /* !SERVER_MODE */
6128  LOG_LSA newflush_upto_lsa; /* Next to be flush */
6129  int first_deleted_arv_num;
6130  int last_deleted_arv_num;
6131  int min_arv_required_for_vacuum;
6132  LOG_PAGEID vacuum_first_pageid;
6133 
6135  {
6136  /* we don't know yet what is the first log page required by vacuum if vacuum_disable is set to true.
6137  * this will block any log archive removal until it is set to false. */
6138  return;
6139  }
6140 
6141  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
6142 
6143  /* Close any log archives that are opened */
6144  if (log_Gl.archive.vdes != NULL_VOLDES)
6145  {
6146  logpb_dismount_log_archive (thread_p);
6147  }
6148 
6149 #if defined(SERVER_MODE)
6150  LSA_COPY (&newflush_upto_lsa, &log_Gl.flushed_lsa_lower_bound);
6151 #else /* SERVER_MODE */
6152 
6153  flush_upto_lsa.pageid = LOGPB_NEXT_ARCHIVE_PAGE_ID;
6154  flush_upto_lsa.offset = NULL_OFFSET;
6155 
6156  pgbuf_flush_checkpoint (thread_p, &flush_upto_lsa, NULL, &newflush_upto_lsa, NULL);
6157 
6158  if ((!LSA_ISNULL (&newflush_upto_lsa) && LSA_LT (&newflush_upto_lsa, &flush_upto_lsa))
6159  || (fileio_synchronize_all (thread_p, false) != NO_ERROR))
6160  {
6161  /* Cannot remove the archives at this moment */
6162  return;
6163  }
6164 
6166  {
6167  if (LSA_LT (&log_Gl.hdr.chkpt_lsa, &flush_upto_lsa))
6168  {
6169  /*
6170  * Reset the checkpoint record to the first possible active page and
6171  * flush the log header before the archives are removed
6172  */
6173  LSA_COPY (&log_Gl.hdr.chkpt_lsa, &flush_upto_lsa);
6174  logpb_flush_header (thread_p);
6175  }
6176  }
6177 #endif /* SERVER_MODE */
6178 
6179  last_deleted_arv_num = log_Gl.hdr.last_arv_num_for_syscrashes;
6180  if (last_deleted_arv_num == -1)
6181  {
6182  last_deleted_arv_num = log_Gl.hdr.nxarv_num;
6183  }
6184 
6185  last_deleted_arv_num--;
6186 
6187  vacuum_first_pageid = vacuum_min_log_pageid_to_keep (thread_p);
6188  if (vacuum_first_pageid != NULL_PAGEID && logpb_is_page_in_archive (vacuum_first_pageid))
6189  {
6190  min_arv_required_for_vacuum = logpb_get_archive_number (thread_p, vacuum_first_pageid);
6191  min_arv_required_for_vacuum--;
6192  last_deleted_arv_num = MIN (last_deleted_arv_num, min_arv_required_for_vacuum);
6193  }
6194 
6195  if (log_Gl.hdr.last_deleted_arv_num + 1 > last_deleted_arv_num)
6196  {
6197  /* Nothing to remove */
6198  return;
6199  }
6200 
6201  first_deleted_arv_num = log_Gl.hdr.last_deleted_arv_num + 1;
6202  if (last_deleted_arv_num >= 0)
6203  {
6204  logpb_remove_archive_logs_internal (thread_p, first_deleted_arv_num, last_deleted_arv_num, info_reason);
6205 
6206  log_Gl.hdr.last_deleted_arv_num = last_deleted_arv_num;
6207  logpb_flush_header (thread_p); /* to get rid of archives */
6208 
6209  _er_log_debug (ARG_FILE_LINE, "first_deleted_arv_num = %d, last_deleted_arv_num = %d", first_deleted_arv_num,
6210  last_deleted_arv_num);
6211  }
6212 }
6213 
6214 /*
6215  * logpb_add_archive_page_info -
6216  *
6217  * return: 0
6218  *
6219  * thread_p(in) :
6220  * arv_num(in) :
6221  * start_page(in):
6222  * end_page(in) :
6223  *
6224  * NOTE:
6225  */
6226 static int
6227 logpb_add_archive_page_info (THREAD_ENTRY * thread_p, int arv_num, LOG_PAGEID start_page, LOG_PAGEID end_page)
6228 {
6229  int rear;
6230 
6232 
6233  rear = logpb_Arv_page_info_table.rear;
6234 
6235  rear = (rear + 1) % ARV_PAGE_INFO_TABLE_SIZE;
6236 
6237  if (logpb_Arv_page_info_table.item_count < ARV_PAGE_INFO_TABLE_SIZE)
6238  {
6239  logpb_Arv_page_info_table.item_count++;
6240  }
6241 
6242  logpb_Arv_page_info_table.rear = rear;
6243  logpb_Arv_page_info_table.page_info[rear].arv_num = arv_num;
6244  logpb_Arv_page_info_table.page_info[rear].start_pageid = start_page;
6245  logpb_Arv_page_info_table.page_info[rear].end_pageid = end_page;
6246 
6247  return 0;
6248 }
6249 
6250 /*
6251  * logpb_get_archive_num_from_info_table -
6252  *
6253  * return: archive_number or -1
6254  *
6255  * thread_p(in) :
6256  * page_id(in) :
6257  *
6258  * NOTE:
6259  */
6260 static int
6262 {
6263  int i, count;
6264 
6266 
6267  for (i = logpb_Arv_page_info_table.rear, count = 0; count < logpb_Arv_page_info_table.item_count;
6268  i = ((i == 0) ? ARV_PAGE_INFO_TABLE_SIZE - 1 : i - 1), count++)
6269  {
6270  if (logpb_Arv_page_info_table.page_info[i].start_pageid <= page_id
6271  && page_id <= logpb_Arv_page_info_table.page_info[i].end_pageid)
6272  {
6273  return logpb_Arv_page_info_table.page_info[i].arv_num;
6274  }
6275  }
6276 
6277  return -1;
6278 }
6279 
6280 /*
6281  * log_remove_archive_logs_internal - Remove all unactive log archives
6282  *
6283  * return: nothing
6284  *
6285  * first(in): first archive to be deleted
6286  * last(in): last archive to be deleted
6287  * info_reason(in): message describing the reason the archives are being deleted
6288  * check_backup(in): when true, avoid deleting archives needed for a restore
6289  *
6290  * NOTE: This routine does the actual deletion and notifies the user
6291  * via the lginf file. This routine does not do any logical verification
6292  * to insure that the archives are no longer needed, so the caller must be
6293  * explicitly careful and insure that there are no circumstances under
6294  * which those archives could possibly be needed before they are deleted.
6295  * Common reasons why they might be needed include a media crash or a
6296  * restore from a fuzzy backup.
6297  */
6298 static int
6299 logpb_remove_archive_logs_internal (THREAD_ENTRY * thread_p, int first, int last, const char *info_reason)
6300 {
6301  char logarv_name[PATH_MAX];
6302  int i;
6303  bool append_log_info = false;
6304  int deleted_count = 0;
6305 
6306  /* Decache any archive remaining in the log_Gl.archive. */
6307  logpb_decache_archive_info (thread_p);
6308 
6309  for (i = first; i <= last; i++)
6310  {
6312 
6313 #if defined(SERVER_MODE)
6315  {
6316  fileio_unformat_and_rename (thread_p, logarv_name, log_Name_removed_archive);
6317  }
6318  else
6319  {
6320  fileio_unformat (thread_p, logarv_name);
6321  }
6322 #else
6323  fileio_unformat (thread_p, logarv_name);
6324 #endif
6325  append_log_info = true;
6326  deleted_count++;
6327  }
6328 
6329  if (append_log_info)
6330  {
6331  logpb_append_archives_removed_to_log_info (first, last, info_reason);
6332  }
6333 
6334  return deleted_count;
6335 }
6336 
6337 /*
6338  * logpb_append_archives_removed_to_log_info - Record deletion of one or more archives
6339  *
6340  * return: nothing
6341  *
6342  * first(in): first archive to be deleted
6343  * last(in): last archive to be deleted
6344  * info_reason(in): message describing the reason the archives are being deleted
6345  *
6346  * NOTE: This routine makes an entry into the loginfo file that the
6347  * given log archives have been removed.
6348  */
6349 static void
6350 logpb_append_archives_removed_to_log_info (int first, int last, const char *info_reason)
6351 {
6352  const char *catmsg;
6353  char logarv_name[PATH_MAX];
6354  char logarv_name_first[PATH_MAX];
6355  int error_code;
6356 
6357  if (info_reason != NULL)
6358  {
6360  if (catmsg == NULL)
6361  {
6362  catmsg = "REMOVE: %d %s to \n%d %s.\nREASON: %s\n";
6363  }
6364 
6366  if (first == last)
6367  {
6368  error_code =
6369  log_dump_log_info (log_Name_info, true, catmsg, first, logarv_name, last, logarv_name, info_reason);
6370  }
6371  else
6372  {
6373  fileio_make_log_archive_name (logarv_name_first, log_Archive_path, log_Prefix, first);
6374  error_code =
6375  log_dump_log_info (log_Name_info, true, catmsg, first, logarv_name_first, last, logarv_name, info_reason);
6376  }
6377  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
6378  {
6379  return;
6380  }
6381  }
6382 }
6383 
6384 /*
6385  *
6386  * FUNCTIONS RELATED TO MISCELANEOUS I/O
6387  *
6388  */
6389 
6390 /*
6391  * logpb_copy_from_log: Copy a portion of the log
6392  *
6393  * arguments:
6394  * area: Area where the portion of the log is copied. (Set as a side effect)
6395  * area_length: the length to copy
6396  * log_lsa: log address of the log data to copy (May be set as a side effect)
6397  * log_pgptr: the buffer containing the log page (May be set as a side effect)
6398  *
6399  * returns/side-effects: nothing
6400  * area is set as a side effect.
6401  * log_lsa, and log_pgptr are set as a side effect.
6402  *
6403  * description: Copy "length" bytes of the log starting at log_lsa->pageid, log_offset onto the given area.
6404  * NOTE: The location of the log is updated to point to the end of the data.
6405  */
6406 void
6407 logpb_copy_from_log (THREAD_ENTRY * thread_p, char *area, int length, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6408 {
6409  int copy_length; /* Length to copy into area */
6410  int area_offset; /* The area offset */
6411 
6412  /*
6413  * If the data is contained in only one buffer, copy the data in one
6414  * statement, otherwise, copy it in parts
6415  */
6416 
6417  if (log_lsa->offset + length < (int) LOGAREA_SIZE)
6418  {
6419  /* The log data is contiguos */
6420  memcpy (area, (char *) log_page_p->area + log_lsa->offset, length);
6421  log_lsa->offset += length;
6422  }
6423  else
6424  {
6425  /* The log data is not contiguos */
6426  area_offset = 0;
6427  while (length > 0)
6428  {
6429  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, 0, log_lsa, log_page_p);
6430  if (log_lsa->offset + length < (int) LOGAREA_SIZE)
6431  {
6432  copy_length = length;
6433  }
6434  else
6435  {
6436  copy_length = LOGAREA_SIZE - (int) (log_lsa->offset);
6437  }
6438  memcpy (area + area_offset, (char *) log_page_p->area + log_lsa->offset, copy_length);
6439  length -= copy_length;
6440  area_offset += copy_length;
6441  log_lsa->offset += copy_length;
6442  }
6443  }
6444 }
6445 
6446 /*
6447  * logpb_verify_length - Verify db and log lengths
6448  *
6449  * return: NO_ERROR if all OK, ER status otherwise
6450  *
6451  * db_fullname(in): Full name of the database
6452  * log_path(in): Directory where the log volumes reside
6453  * log_prefix(in): Name of the log volumes. It is usually set as database
6454  * name. For example, if the value is equal to "db", the
6455  * names of the log volumes created are as follow:
6456  * Active_log = db_logactive
6457  * Archive_logs = db_logarchive.0
6458  * db_logarchive.1
6459  * .
6460  * .
6461  * .
6462  * db_logarchive.n
6463  * Log_information = db_loginfo
6464  * Database Backup = db_backup
6465  *
6466  * NOTE: Make sure that any database name will not be overpassed.
6467  */
6468 static int
6469 logpb_verify_length (const char *db_fullname, const char *log_path, const char *log_prefix)
6470 {
6471  int volmax_suffix;
6472  int length;
6473  const char *dbname;
6474  long int filename_max;
6475  long int pathname_max;
6476 
6477  volmax_suffix = fileio_get_volume_max_suffix ();
6478 
6479  dbname = fileio_get_base_file_name (db_fullname);
6480  if (fileio_get_max_name (db_fullname, &filename_max, &pathname_max) < 0)
6481  {
6482  return ER_FAILED;
6483  }
6484 
6485  if (pathname_max > DB_MAX_PATH_LENGTH)
6486  {
6487  pathname_max = DB_MAX_PATH_LENGTH;
6488  }
6489 
6490  /*
6491  * Make sure that names of volumes (information and log volumes), that is,
6492  * OS files will not exceed the maximum allowed value.
6493  */
6494 
6495  if ((int) (strlen (dbname) + 1 + volmax_suffix) > filename_max)
6496  {
6497  /* The name of the volume is too long */
6499  filename_max - volmax_suffix - 1);
6501  }
6502 
6503  if ((int) (strlen (log_prefix) + 1) > filename_max || (strlen (log_prefix) + 1) > MAXLOGNAME)
6504  {
6505  /* Bad prefix log name */
6507  (((int) MAXLOGNAME > filename_max) ? filename_max - 1 : (int) MAXLOGNAME - 1));
6509  }
6510 
6511  /*
6512  * Make sure that the length for the volume is OK
6513  */
6514 
6515  if ((int) (strlen (db_fullname) + 1 + volmax_suffix) > pathname_max)
6516  {
6517  /* The full name of the database is too long */
6519  strlen (db_fullname) + 1, pathname_max);
6521  }
6522 
6523  /*
6524  * First create a new log for the new database. This log is not a copy of
6525  * of the old log; it is a newly created one.
6526  */
6527 
6528  if (log_path != NULL)
6529  {
6530  length = (int) (strlen (log_path) + strlen (log_prefix) + 2);
6531  }
6532  else
6533  {
6534  length = (int) strlen (log_prefix) + 1;
6535  }
6536 
6537  if (length + volmax_suffix > pathname_max)
6538  {
6539  /*
6540  * Database name is too long.
6541  * Path + prefix < pathname_max - 2
6542  */
6544  pathname_max - 2);
6545  return ER_LOG_NAME_IS_TOO_LONG;
6546  }
6547 
6548  return NO_ERROR;
6549 }
6550 
6551 /*
6552  * logpb_initialize_log_names - Initialize the names of log volumes and files
6553  *
6554  * return: nothing
6555  *
6556  * db_fullname(in): Full name of the database
6557  * logpath(in): Directory where the log volumes reside
6558  * prefix_logname(in): Name of the log volumes. It is usually set as database
6559  * name. For example, if the value is equal to "db", the
6560  * names of the log volumes created are as follow:
6561  * Active_log = db_logactive
6562  * Archive_logs = db_logarchive.0
6563  * db_logarchive.1
6564  * .
6565  * .
6566  * .
6567  * db_logarchive.n
6568  * Log_information = db_loginfo
6569  * Database Backup = db_backup
6570  *
6571  * NOTE: Initialize name of log volumes and files
6572  */
6573 int
6574 logpb_initialize_log_names (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
6575  const char *prefix_logname)
6576 {
6577  int error_code = NO_ERROR;
6578 
6579  error_code = logpb_verify_length (db_fullname, logpath, prefix_logname);
6580  if (error_code != NO_ERROR)
6581  {
6582  /* Names are too long */
6583  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "logpb_initialize_log_names");
6584 
6585  return error_code;
6586  }
6587 
6588  /* Save the log Path */
6589 
6590  if (logpath != NULL)
6591  {
6592  strcpy (log_Path, logpath);
6593  }
6594  else
6595  {
6596  strcpy (log_Path, ".");
6597  }
6598 
6599  strcpy (log_Archive_path, log_Path);
6600 
6601  /* Save the log Prefix */
6602  strcpy (log_Prefix, prefix_logname);
6603 
6604  /*
6605  * Build Name of log active
6606  */
6613  log_Db_fullname = db_fullname;
6614 
6615  return error_code;
6616 }
6617 
6618 /*
6619  * logpb_exist_log - Find if given log exists
6620  *
6621  * return:
6622  *
6623  * db_fullname(in): Full name of the database
6624  * logpath(in): Directory where the log volumes reside
6625  * prefix_logname(in): Name of the log volumes. It is usually set as database
6626  * name. For example, if the value is equal to "db", the
6627  * names of the log volumes created are as follow:
6628  * Active_log = db_logactive
6629  * Archive_logs = db_logarchive.0
6630  * db_logarchive.1
6631  * .
6632  * .
6633  * .
6634  * db_logarchive.n
6635  * Log_information = db_loginfo
6636  * Database Backup = db_backup
6637  *
6638  * NOTE: Find if the log associated with the aboive database exists.
6639  */
6640 bool
6641 logpb_exist_log (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
6642 {
6643  /* Is the system restarted ? */
6644  if (!logpb_is_pool_initialized ())
6645  {
6646  if (logpb_initialize_log_names (thread_p, db_fullname, logpath, prefix_logname) != NO_ERROR)
6647  {
6648  return false;
6649  }
6650  }
6651 
6653 }
6654 
6655 void
6656 logpb_checkpoint_trans (LOG_INFO_CHKPT_TRANS * chkpt_entries, log_tdes * tdes, int &ntrans, int &ntops,
6657  LOG_LSA & smallest_lsa)
6658 {
6659  LOG_INFO_CHKPT_TRANS *chkpt_entry = &chkpt_entries[ntrans];
6660  if (tdes != NULL && tdes->trid != NULL_TRANID && !LSA_ISNULL (&tdes->tail_lsa))
6661  {
6662  chkpt_entry->isloose_end = tdes->isloose_end;
6663  chkpt_entry->trid = tdes->trid;
6664  chkpt_entry->state = tdes->state;
6665  LSA_COPY (&chkpt_entry->head_lsa, &tdes->head_lsa);
6666  LSA_COPY (&chkpt_entry->tail_lsa, &tdes->tail_lsa);
6667  if (chkpt_entry->state == TRAN_UNACTIVE_ABORTED)
6668  {
6669  /*
6670  * Transaction is in the middle of an abort, since rollback does
6671  * is not run in a critical section. Set the undo point to be the
6672  * same as its tail. The recovery process will read the last
6673  * record which is likely a compensating one, and find where to
6674  * continue a rollback operation.
6675  */
6676  LSA_COPY (&chkpt_entry->undo_nxlsa, &tdes->tail_lsa);
6677  }
6678  else
6679  {
6680  LSA_COPY (&chkpt_entry->undo_nxlsa, &tdes->undo_nxlsa);
6681  }
6682 
6683  LSA_COPY (&chkpt_entry->posp_nxlsa, &tdes->posp_nxlsa);
6684  LSA_COPY (&chkpt_entry->savept_lsa, &tdes->savept_lsa);
6685  LSA_COPY (&chkpt_entry->tail_topresult_lsa, &tdes->tail_topresult_lsa);
6686  LSA_COPY (&chkpt_entry->start_postpone_lsa, &tdes->rcv.tran_start_postpone_lsa);
6687  strncpy (chkpt_entry->user_name, tdes->client.get_db_user (), LOG_USERNAME_MAX);
6688  ntrans++;
6689  if (tdes->topops.last >= 0 && (tdes->state == TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE))
6690  {
6691  ntops += tdes->topops.last + 1;
6692  }
6693 
6694  if (LSA_ISNULL (&smallest_lsa) || LSA_GT (&smallest_lsa, &tdes->head_lsa))
6695  {
6696  LSA_COPY (&smallest_lsa, &tdes->head_lsa);
6697  }
6698  }
6699 }
6700 
6701 int
6703  LOG_INFO_CHKPT_TRANS * chkpt_trans, LOG_REC_CHKPT & tmp_chkpt, log_tdes * tdes, int &ntops,
6704  size_t & length_all_tops)
6705 {
6706  if (tdes != NULL && tdes->trid != NULL_TRANID
6708  {
6709  /* this transaction is running system operation postpone or an atomic system operation
6710  * note: we cannot compare tdes->state with TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE. we are
6711  * not synchronizing setting transaction state.
6712  * however, setting tdes->rcv.sysop_start_postpone_lsa is protected by
6713  * log_Gl.prior_info.prior_lsa_mutex. so we check this instead of state.
6714  */
6715  if (ntops >= tmp_chkpt.ntops)
6716  {
6718  length_all_tops = sizeof (*chkpt_topops) * tmp_chkpt.ntops;
6719  LOG_INFO_CHKPT_SYSOP *ptr = (LOG_INFO_CHKPT_SYSOP *) realloc (chkpt_topops, length_all_tops);
6720  if (ptr == NULL)
6721  {
6722  free_and_init (chkpt_trans);
6723  log_Gl.prior_info.prior_lsa_mutex.unlock ();
6724  TR_TABLE_CS_EXIT (thread_p);
6725  return ER_FAILED;
6726  }
6727  chkpt_topops = ptr;
6728  }
6729 
6730  LOG_INFO_CHKPT_SYSOP *chkpt_topop = &chkpt_topops[ntops];
6731  chkpt_topop->trid = tdes->trid;
6733  chkpt_topop->atomic_sysop_start_lsa = tdes->rcv.atomic_sysop_start_lsa;
6734  ntops++;
6735  }
6736  return NO_ERROR;
6737 }
6738 
6739 /*
6740  * logpb_checkpoint - Execute a fuzzy checkpoint
6741  *
6742  * return: pageid where a redo will start
6743  *
6744  */
6745 LOG_PAGEID
6747 {
6748 #define detailed_er_log(...) if (detailed_logging) _er_log_debug (ARG_FILE_LINE, __VA_ARGS__)
6749 
6750  LOG_TDES *tdes; /* System transaction descriptor */
6751  LOG_TDES *act_tdes; /* Transaction descriptor of an active transaction */
6752  LOG_REC_CHKPT *chkpt, tmp_chkpt; /* Checkpoint log records */
6753  LOG_INFO_CHKPT_TRANS *chkpt_trans; /* Checkpoint tdes */
6754  LOG_INFO_CHKPT_TRANS *chkpt_one; /* Checkpoint tdes for one tran */
6755  LOG_INFO_CHKPT_SYSOP *chkpt_topops; /* Checkpoint top system operations that are in commit postpone
6756  * mode */
6757  LOG_INFO_CHKPT_SYSOP *chkpt_topone; /* One top system ope */
6758  LOG_LSA chkpt_lsa; /* copy of log_Gl.hdr.chkpt_lsa */
6759  LOG_LSA chkpt_redo_lsa; /* copy of log_Gl.chkpt_redo_lsa */
6760  LOG_LSA newchkpt_lsa; /* New address of the checkpoint record */
6761  LOG_LSA smallest_lsa;
6762  unsigned int nobj_locks; /* Avg number of locks */
6763  char logarv_name[PATH_MAX]; /* Archive name */
6764  char logarv_name_first[PATH_MAX]; /* Archive name */
6765  int ntrans; /* Number of trans */
6766  int ntops; /* Number of total active top actions */
6767  int length_all_chkpt_trans;
6768  size_t length_all_tops = 0;
6769  int i;
6770  const char *catmsg;
6771  VOLID volid;
6772  VOLID curr_last_perm_volid;
6773  int error_code = NO_ERROR;
6774  LOG_PAGEID smallest_pageid;
6775  int first_arv_num_not_needed;
6776  int last_arv_num_not_needed;
6777  LOG_PRIOR_NODE *node;
6778  void *ptr;
6779  int flushed_page_cnt = 0, vdes;
6780  bool detailed_logging = prm_get_bool_value (PRM_ID_LOG_CHKPT_DETAILED);
6781  // *INDENT-OFF*
6783  // *INDENT-ON*
6784 
6785  LOG_CS_ENTER (thread_p);
6786 
6787 #if defined(SERVER_MODE)
6789  {
6790  LOG_CS_EXIT (thread_p);
6791  return NULL_PAGEID;
6792  }
6793 
6794  /*
6795  * Critical section is entered several times to allow other transaction to
6796  * use the log manger
6797  */
6798 #endif /* SERVER_MODE */
6799 
6801 
6804  er_log_debug (ARG_FILE_LINE, "start checkpoint\n");
6805 
6806  /*
6807  * Indicate that the checkpoint process is running. Don't run another one,
6808  * until we are done with the present one.
6809  */
6810 
6812 
6814  if (tdes == NULL)
6815  {
6816  goto error_cannot_chkpt;
6817  }
6818 
6819  /*
6820  * FLUSH all append LOG PAGES and flush all DIRTY DATA PAGES whose LSA
6821  * are SMALLER OR EQUAL than newchkpt_lsa value and find the next redo
6822  * point.
6823  */
6824 
6825  (void) pthread_mutex_lock (&log_Gl.chkpt_lsa_lock);
6826  LSA_COPY (&chkpt_lsa, &log_Gl.hdr.chkpt_lsa);
6827  LSA_COPY (&chkpt_redo_lsa, &log_Gl.chkpt_redo_lsa);
6828  pthread_mutex_unlock (&log_Gl.chkpt_lsa_lock);
6829 
6830  logpb_flush_pages_direct (thread_p);
6831 
6832  /* MARK THE CHECKPOINT PROCESS */
6834  if (node == NULL)
6835  {
6836  goto error_cannot_chkpt;
6837  }
6838 
6839  newchkpt_lsa = prior_lsa_next_record (thread_p, node, tdes);
6840  assert (!LSA_ISNULL (&newchkpt_lsa));
6841 
6842  /*
6843  * Modify log header to record present checkpoint. The header is flushed
6844  * later
6845  */
6846 
6847  LOG_CS_EXIT (thread_p);
6848 
6849  detailed_er_log ("logpb_checkpoint: call logtb_reflect_global_unique_stats_to_btree()\n");
6851  {
6852  goto error_cannot_chkpt;
6853  }
6854 
6855  detailed_er_log ("logpb_checkpoint: call pgbuf_flush_checkpoint()\n");
6856  if (pgbuf_flush_checkpoint (thread_p, &newchkpt_lsa, &chkpt_redo_lsa, &tmp_chkpt.redo_lsa, &flushed_page_cnt) !=
6857  NO_ERROR)
6858  {
6859  goto error_cannot_chkpt;
6860  }
6861 
6862  detailed_er_log ("logpb_checkpoint: call fileio_synchronize_all()\n");
6863  if (fileio_synchronize_all (thread_p, false) != NO_ERROR)
6864  {
6865  goto error_cannot_chkpt;
6866  }
6867 
6868  LOG_CS_ENTER (thread_p);
6869 
6870  if (LSA_ISNULL (&tmp_chkpt.redo_lsa))
6871  {
6872  LSA_COPY (&tmp_chkpt.redo_lsa, &newchkpt_lsa);
6873  }
6874 
6875  assert (LSA_LE (&tmp_chkpt.redo_lsa, &newchkpt_lsa));
6876 
6877 #if defined(SERVER_MODE)
6878  /* Save lower bound of flushed lsa */
6879  if (!LSA_ISNULL (&tmp_chkpt.redo_lsa))
6880  {
6881  if (LSA_ISNULL (&log_Gl.flushed_lsa_lower_bound) || LSA_GT (&tmp_chkpt.redo_lsa, &log_Gl.flushed_lsa_lower_bound))
6882  {
6883  LSA_COPY (&log_Gl.flushed_lsa_lower_bound, &tmp_chkpt.redo_lsa);
6884  }
6885  }
6886 #endif /* SERVER_MODE */
6887 
6888  TR_TABLE_CS_ENTER (thread_p);
6889 
6890  /* allocate memory space for the transaction descriptors */
6892  length_all_chkpt_trans = sizeof (*chkpt_trans) * tmp_chkpt.ntrans;
6893 
6894  chkpt_trans = (LOG_INFO_CHKPT_TRANS *) malloc (length_all_chkpt_trans);
6895  if (chkpt_trans == NULL)
6896  {
6897  TR_TABLE_CS_EXIT (thread_p);
6898  goto error_cannot_chkpt;
6899  }
6900 
6902 
6903  /* CHECKPOINT THE TRANSACTION TABLE */
6904 
6905  LSA_SET_NULL (&smallest_lsa);
6906  for (i = 0, ntrans = 0, ntops = 0; i < log_Gl.trantable.num_total_indices; i++)
6907  {
6908  /*
6909  * Don't checkpoint current system transaction. That is, the one of
6910  * checkpoint process
6911  */
6912  if (i == LOG_SYSTEM_TRAN_INDEX)
6913  {
6914  continue;
6915  }
6916  act_tdes = LOG_FIND_TDES (i);
6917  assert (ntrans < tmp_chkpt.ntrans);
6918  logpb_checkpoint_trans (chkpt_trans, act_tdes, ntrans, ntops, smallest_lsa);
6919  }
6920 
6921  /*
6922  * Reset the structure to the correct number of transactions and
6923  * recalculate the length
6924  */
6925  tmp_chkpt.ntrans = ntrans;
6926  length_all_chkpt_trans = sizeof (*chkpt_trans) * tmp_chkpt.ntrans;
6927 
6928  /*
6929  * Scan again if there were any top system operations in the process of being committed.
6930  * NOTE that we checkpoint top system operations only when there are in the
6931  * process of commit. Not knowledge of top system operations that are not
6932  * in the process of commit is required since if there is a crash, the system
6933  * operation is aborted as part of the transaction.
6934  */
6935 
6936  chkpt_topops = NULL;
6937  if (ntops > 0)
6938  {
6940  length_all_tops = sizeof (*chkpt_topops) * tmp_chkpt.ntops;
6941  chkpt_topops = (LOG_INFO_CHKPT_SYSOP *) malloc (length_all_tops);
6942  if (chkpt_topops == NULL)
6943  {
6944  free_and_init (chkpt_trans);
6945  log_Gl.prior_info.prior_lsa_mutex.unlock ();
6946  TR_TABLE_CS_EXIT (thread_p);
6947  goto error_cannot_chkpt;
6948  }
6949 
6950  /* CHECKPOINTING THE TOP ACTIONS */
6951  for (i = 0, ntrans = 0, ntops = 0; i < log_Gl.trantable.num_total_indices; i++)
6952  {
6953  /*
6954  * Don't checkpoint current system transaction. That is, the one of
6955  * checkpoint process
6956  */
6957  if (i == LOG_SYSTEM_TRAN_INDEX)
6958  {
6959  continue;
6960  }
6961  act_tdes = LOG_FIND_TDES (i);
6962  error_code =
6963  logpb_checkpoint_topops (thread_p, chkpt_topops, chkpt_trans, tmp_chkpt, act_tdes, ntops, length_all_tops);
6964  if (error_code != NO_ERROR)
6965  {
6966  goto error_cannot_chkpt;
6967  }
6968  }
6969  }
6970  else
6971  {
6972  tmp_chkpt.ntops = 1;
6973  length_all_tops = sizeof (*chkpt_topops) * tmp_chkpt.ntops;
6974  chkpt_topops = (LOG_INFO_CHKPT_SYSOP *) malloc (length_all_tops);
6975  if (chkpt_topops == NULL)
6976  {
6977  free_and_init (chkpt_trans);
6978  log_Gl.prior_info.prior_lsa_mutex.unlock ();
6979  TR_TABLE_CS_EXIT (thread_p);
6980  goto error_cannot_chkpt;
6981  }
6982  }
6983 
6984  // Checkpoint system transactions' topops
6985  // *INDENT-OFF*
6986  mapper = [thread_p, &chkpt_topops, &chkpt_trans, &tmp_chkpt, &ntops, &length_all_tops, &error_code] (log_tdes &tdes)
6987  {
6988  error_code =
6989  logpb_checkpoint_topops (thread_p, chkpt_topops, chkpt_trans, tmp_chkpt, &tdes, ntops, length_all_tops);
6990  };
6991 
6993  // *INDENT-ON*
6994  if (error_code != NO_ERROR)
6995  {
6996  goto error_cannot_chkpt;
6997  }
6998 
6999  assert (sizeof (*chkpt_topops) * ntops <= length_all_tops);
7000  tmp_chkpt.ntops = ntops;
7001  length_all_tops = sizeof (*chkpt_topops) * tmp_chkpt.ntops;
7002 
7003  node =
7004  prior_lsa_alloc_and_copy_data (thread_p, LOG_END_CHKPT, RV_NOT_DEFINED, NULL, length_all_chkpt_trans,
7005  (char *) chkpt_trans, (int) length_all_tops, (char *) chkpt_topops);
7006  if (node == NULL)
7007  {
7008  free_and_init (chkpt_trans);
7009 
7010  if (chkpt_topops != NULL)
7011  {
7012  free_and_init (chkpt_topops);
7013  }
7014  log_Gl.prior_info.prior_lsa_mutex.unlock ();
7015  TR_TABLE_CS_EXIT (thread_p);
7016  goto error_cannot_chkpt;
7017  }
7018 
7019  chkpt = (LOG_REC_CHKPT *) node->data_header;
7020  *chkpt = tmp_chkpt;
7021 
7022  prior_lsa_next_record_with_lock (thread_p, node, tdes);
7023 
7024  log_Gl.prior_info.prior_lsa_mutex.unlock ();
7025 
7026  TR_TABLE_CS_EXIT (thread_p);
7027 
7028  free_and_init (chkpt_trans);
7029 
7030  /* Any topops to log ? */
7031  if (chkpt_topops != NULL)
7032  {
7033  free_and_init (chkpt_topops);
7034  }
7035 
7036  /*
7037  * END append
7038  * Flush the page since we are going to flush the log header which
7039  * reflects the new location of the last checkpoint log record
7040  */
7041  logpb_flush_pages_direct (thread_p);
7042  detailed_er_log ("logpb_checkpoint: call logpb_flush_all_append_pages()\n");
7043 
7044  /*
7045  * Flush the log data header and update all checkpoints in volumes to
7046  * point to new checkpoint
7047  */
7048 
7049  /* Average the number of active transactions and locks */
7050  nobj_locks = lock_get_number_object_locks ();
7051  log_Gl.hdr.avg_ntrans = (log_Gl.hdr.avg_ntrans + ntrans) >> 1;
7052  log_Gl.hdr.avg_nlocks = (log_Gl.hdr.avg_nlocks + nobj_locks) >> 1;
7053 
7054  /* Flush the header */
7055  (void) pthread_mutex_lock (&log_Gl.chkpt_lsa_lock);
7056  if (LSA_LT (&log_Gl.hdr.chkpt_lsa, &newchkpt_lsa))
7057  {
7058  LSA_COPY (&log_Gl.hdr.chkpt_lsa, &newchkpt_lsa);
7059  }
7060  LSA_COPY (&chkpt_lsa, &log_Gl.hdr.chkpt_lsa);
7061 
7062  if (LSA_ISNULL (&smallest_lsa))
7063  {
7065  }
7066  else
7067  {
7068  LSA_COPY (&log_Gl.hdr.smallest_lsa_at_last_chkpt, &smallest_lsa);
7069  }
7070  LSA_COPY (&log_Gl.chkpt_redo_lsa, &tmp_chkpt.redo_lsa);
7071 
7072  pthread_mutex_unlock (&log_Gl.chkpt_lsa_lock);
7073 
7074  detailed_er_log ("logpb_checkpoint: call logpb_flush_header()\n");
7075  logpb_flush_header (thread_p);
7076 
7077  /*
7078  * Exit from the log critical section since we are going to call another
7079  * module which may be blocked on a lock.
7080  */
7081 
7082  LOG_CS_EXIT (thread_p);
7083 
7084  /*
7085  * Record the checkpoint address on every volume header
7086  */
7087  curr_last_perm_volid = xboot_find_last_permanent (thread_p);
7088 
7089  for (volid = LOG_DBFIRST_VOLID; volid != NULL_VOLID && volid <= curr_last_perm_volid;
7090  volid = fileio_find_next_perm_volume (thread_p, volid))
7091  {
7092  /* When volid is greater than boot_Db_parm->last_perm_volid, it means that the volume is now adding. We don't
7093  * need to care for the new volumes in here. */
7094  if (disk_set_checkpoint (thread_p, volid, &chkpt_lsa) != NO_ERROR)
7095  {
7096  goto error_cannot_chkpt;
7097  }
7098 
7099  /* When setting the checkpoint, the header page modification is not logged. However, other concurrent
7100  * transaction may modify meanwhile the header page (with logging). Since writing data page is preceded by
7101  * log sync, we are sure that WAL is not violated. We only need to sync the data volume. Probably, it is better
7102  * to sync it now - as soon as possible. If we are postponing volume sync, we may write on disk more data pages
7103  * twice (the data pages modified before checkpoint - other than volume header page, written on disk at the
7104  * beginning of the checkpoint, modified again by concurrent transaction, written on disk again in checkpoint
7105  * due to volume header page modification).
7106  */
7107  vdes = fileio_get_volume_descriptor (volid);
7108  if (fileio_synchronize (thread_p, vdes, fileio_get_volume_label (vdes, PEEK), FILEIO_SYNC_ALSO_FLUSH_DWB) != vdes)
7109  {
7110  goto error_cannot_chkpt;
7111  }
7112  }
7113 
7114  /*
7115  * Get the critical section again, so we can check if any archive can be
7116  * declare as un-needed
7117  */
7118 
7119  LOG_CS_ENTER (thread_p);
7120 
7121  /*
7122  * If the log archives are not needed for any normal undos and redos,
7123  * indicate so. However, the log archives may be needed during media
7124  * crash recovery.
7125  */
7126  smallest_pageid = NULL_PAGEID;
7127  first_arv_num_not_needed = last_arv_num_not_needed = -1;
7128 
7130  {
7131  LOG_LSA lsa;
7132 
7133 #if defined(SERVER_MODE)
7134  smallest_pageid = MIN (log_Gl.flushed_lsa_lower_bound.pageid, tmp_chkpt.redo_lsa.pageid);
7135 #else
7136  smallest_pageid = tmp_chkpt.redo_lsa.pageid;
7137 #endif
7138 
7139  logtb_find_smallest_lsa (thread_p, &lsa);
7140 
7141  if (lsa.pageid != NULL_PAGEID)
7142  {
7143  smallest_pageid = MIN (smallest_pageid, lsa.pageid);
7144  }
7145 
7146  if (logpb_is_page_in_archive (smallest_pageid))
7147  {
7148  int arv_num;
7149 
7150  if ((logpb_fetch_from_archive (thread_p, smallest_pageid, NULL, &arv_num, NULL, true) == NULL)
7151  || (arv_num <= log_Gl.hdr.last_arv_num_for_syscrashes))
7152  {
7153  first_arv_num_not_needed = last_arv_num_not_needed = -1;
7154  }
7155  else
7156  {
7157  first_arv_num_not_needed = log_Gl.hdr.last_arv_num_for_syscrashes;
7158  last_arv_num_not_needed = arv_num - 1;
7159  }
7160  }
7161  else
7162  {
7163  first_arv_num_not_needed = log_Gl.hdr.last_arv_num_for_syscrashes;
7164  last_arv_num_not_needed = log_Gl.hdr.nxarv_num - 1;
7165  }
7166 
7167  if (first_arv_num_not_needed != -1)
7168  {
7169  log_Gl.hdr.last_arv_num_for_syscrashes = last_arv_num_not_needed + 1;
7170 
7171  /* Close any log archives that are opened */
7172  if (log_Gl.archive.vdes != NULL_VOLDES)
7173  {
7174  logpb_dismount_log_archive (thread_p);
7175  }
7176 
7177  /* This is OK since we have already flushed the log header page */
7178  if (first_arv_num_not_needed == last_arv_num_not_needed)
7179  {
7180  fileio_make_log_archive_name (logarv_name, log_Archive_path, log_Prefix, first_arv_num_not_needed);
7181  catmsg =
7183  if (catmsg == NULL)
7184  {
7185  catmsg = "COMMENT: Log archive %s is not needed any longer unless a database media crash occurs.\n";
7186  }
7187  error_code = log_dump_log_info (log_Name_info, true, catmsg, logarv_name);
7188  }
7189  else
7190  {
7191  fileio_make_log_archive_name (logarv_name_first, log_Archive_path, log_Prefix, first_arv_num_not_needed);
7192  fileio_make_log_archive_name (logarv_name, log_Archive_path, log_Prefix, last_arv_num_not_needed);
7193 
7194  catmsg =
7197  if (catmsg == NULL)
7198  {
7199  catmsg =
7200  "COMMENT: Log archives from %s to %s are not"
7201  " needed any longer unless a database media crash occurs.\n";
7202  }
7203  error_code = log_dump_log_info (log_Name_info, true, catmsg, logarv_name_first, logarv_name);
7204  }
7205  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
7206  {
7207  goto error_cannot_chkpt;
7208  }
7209 
7210  logpb_flush_header (thread_p); /* Yes, one more time, to get rid of archives */
7211  }
7212  }
7213 
7214  /*
7215  * Checkpoint process is not running any longer. Indicate when do we expect
7216  * it to run.
7217  */
7218 
7220  /*
7221  * Clear all tail and heads information of current system transaction
7222  * todo - is it safe to clear though?
7223  */
7224  logtb_clear_tdes (thread_p, tdes);
7225 
7226  LOG_CS_EXIT (thread_p);
7227 
7228 #if 0
7229  /* have to sync log vol, data vol */
7230  fileio_synchronize_all (thread_p, true /* include_log */ );
7231 #endif
7232 
7234 
7236  log_Gl.chkpt_redo_lsa.pageid, flushed_page_cnt);
7237  er_log_debug (ARG_FILE_LINE, "end checkpoint\n");
7238 
7239  return tmp_chkpt.redo_lsa.pageid;
7240 
7241  /* ******** */
7242 error_cannot_chkpt:
7243  if (!LOG_CS_OWN_WRITE_MODE (thread_p))
7244  {
7245  LOG_CS_ENTER (thread_p);
7246  }
7247 
7248  /* to immediately execute the next checkpoint. */
7250 
7251  LOG_CS_EXIT (thread_p);
7252 
7253  return NULL_PAGEID;
7254 
7255 #undef detailed_er_log
7256 }
7257 
7258 /*
7259  * logpb_dump_checkpoint_trans - Dump checkpoint transactions
7260  *
7261  * return: nothing
7262  *
7263  * length(in): Length to dump in bytes
7264  * data(in): The data being logged
7265  *
7266  * NOTE: Dump a checkpoint transactions structure.
7267  */
7268 void
7269 logpb_dump_checkpoint_trans (FILE * out_fp, int length, void *data)
7270 {
7271  int ntrans, i;
7272  LOG_INFO_CHKPT_TRANS *chkpt_trans, *chkpt_one; /* Checkpoint tdes */
7273 
7274  chkpt_trans = (LOG_INFO_CHKPT_TRANS *) data;
7275  ntrans = length / sizeof (*chkpt_trans);
7276 
7277  /* Start dumping each checkpoint transaction descriptor */
7278 
7279  for (i = 0; i < ntrans; i++)
7280  {
7281  chkpt_one = &chkpt_trans[i];
7282  fprintf (out_fp,
7283  " Trid = %d, State = %s, isloose_end = %d,\n"
7284  " Head_lsa = %lld|%d, Tail_lsa = %lld|%d, UndoNxtLSA = %lld|%d,\n"
7285  " Postpone_lsa = %lld|%d, Save_lsa = %lld|%d, Tail_topresult_lsa = %lld|%d,\n"
7286  " Client_User: name=%s.\n", chkpt_one->trid, log_state_string (chkpt_one->state),
7287  chkpt_one->isloose_end, (long long int) chkpt_one->head_lsa.pageid,
7288  (int) chkpt_one->head_lsa.offset, (long long int) chkpt_one->tail_lsa.pageid,
7289  (int) chkpt_one->tail_lsa.offset, (long long int) chkpt_one->undo_nxlsa.pageid,
7290  (int) chkpt_one->undo_nxlsa.offset, (long long int) chkpt_one->posp_nxlsa.pageid,
7291  (int) chkpt_one->posp_nxlsa.offset, (long long int) chkpt_one->savept_lsa.pageid,
7292  (int) chkpt_one->savept_lsa.offset, (long long int) chkpt_one->tail_topresult_lsa.pageid,
7293  (int) chkpt_one->tail_topresult_lsa.offset, chkpt_one->user_name);
7294  }
7295  (void) fprintf (out_fp, "\n");
7296 }
7297 
7298 /*
7299  * logpb_backup_for_volume - Execute a full backup for the given volume
7300  *
7301  * return: NO_ERROR if all OK, ER status otherwise
7302  *
7303  * volid(in): The identifier of the volume to backup
7304  * chkpt_lsa(in): Checkpoint of the backup process
7305  * session(in/out): The session array which is set as a side effect.
7306  * only_updated(in):
7307  *
7308  * NOTE: The volume with the given volume identifier is backed up on
7309  * the given fullname_backup. The backup that is taken is a fuzzy
7310  * snapshot of the volume since updates to the volume may be in
7311  * progress. Thus, the backup may contain some uncommitted data.
7312  * Even worse, the backup is performed using the disk directly.
7313  * That is, we copy the pages of the disk without going through
7314  * the page buffer pool to avoid disrupting the locality of the
7315  * page buffers (e.g., a query executed by another transaction)
7316  * For temp volumes, incremental backups are not allowed (because
7317  * of logging issues) so always save the system pages of temp
7318  * volumes.
7319  */
7320 static int
7321 logpb_backup_for_volume (THREAD_ENTRY * thread_p, VOLID volid, LOG_LSA * chkpt_lsa, FILEIO_BACKUP_SESSION * session,
7322  bool only_updated)
7323 {
7324  DISK_VOLPURPOSE volpurpose;
7325  PAGEID vol_sys_lastpage;
7326  int vdes;
7327  int error_code = NO_ERROR;
7328 
7329  /*
7330  * Determine the purpose of the volume. For most volumes we need to
7331  * backup every page, but for temporary volumes we only need the system
7332  * pages.
7333  */
7334  if (xdisk_get_purpose_and_sys_lastpage (thread_p, volid, &volpurpose, &vol_sys_lastpage) == NULL_VOLID)
7335  {
7336  error_code = ER_FAILED;
7337  return error_code;
7338  }
7339  else if (volpurpose == DB_TEMPORARY_DATA_PURPOSE)
7340  {
7341  /*
7342  * Do not allow incremental backups of temp volumes; but since we
7343  * only backup the system pages, they be only a handfull of pages.
7344  */
7345  only_updated = false;
7346  }
7347  else
7348  {
7349  vol_sys_lastpage = -1; /* must backup entire volume */
7350  }
7351 
7352  /*
7353  * Reset the checkpoint of the volume to backup and flush all its dirty
7354  * pages, so that the the backup reflects the actual state of the volume
7355  * as much as possible
7356  */
7357  error_code = disk_set_checkpoint (thread_p, volid, chkpt_lsa);
7358  if (error_code != NO_ERROR)
7359  {
7360  return error_code;
7361  }
7362 
7363  LOG_CS_ENTER (thread_p);
7364  logpb_flush_pages_direct (thread_p);
7365  LOG_CS_EXIT (thread_p);
7366 
7367  error_code = pgbuf_flush_all_unfixed (thread_p, volid);
7368  if (error_code != NO_ERROR)
7369  {
7370  return error_code;
7371  }
7372 
7373  vdes = fileio_get_volume_descriptor (volid);
7374  if (fileio_synchronize (thread_p, vdes, fileio_get_volume_label (vdes, PEEK), FILEIO_SYNC_ALSO_FLUSH_DWB) != vdes)
7375  {
7376  return ER_FAILED;
7377  }
7378 
7379  /*
7380  * Create the backup file/volume and copy the content onto it.
7381  *
7382  * Note that the copy is done from disk to disk. The page buffer pool is
7383  * not used. Thus, some more recent version of some copied pages may be
7384  * present in the buffer pool. We copy the database without using the page
7385  * buffer pool to avoid disrupting the locality of pages in the page
7386  * buffer pool and avoid the overhead of calling the page buffer manager.
7387  */
7388 
7389  error_code =
7390  fileio_backup_volume (thread_p, session, fileio_get_volume_label (volid, PEEK), volid, vol_sys_lastpage,
7391  only_updated);
7392 
7393  return error_code;
7394 }
7395 
7396 /*
7397  * logpb_backup - Execute a level backup for the given database volume
7398  *
7399  * return: NO_ERROR if all OK, ER status otherwise
7400  *
7401  * num_perm_vols(in): Number of permanent volumes
7402  * allbackup_path(in): Location where information volumes are
7403  * backed up. If NULL is given, the following
7404  * defaults are assumed to back up each
7405  * information volume:
7406  * - If file "fileof_vols_and_backup_paths" is
7407  * given, the path to backup each volume is
7408  * found in this file.
7409  * - All information volumes are backed up on
7410  * the same location where the log files are
7411  * located.
7412  * backup_level(in): backup levels allowed: 0 - Full (default),
7413  * 1 - Incremental1, 2 - Incremental
7414  * delete_unneeded_logarchives(in): Whetear to remove log archives that are
7415  * not needed any longer to recovery from
7416  * crashes when the backup just created is
7417  * used.
7418  * backup_verbose_file_path(in): verbose mode file path
7419  * num_threads(in): number of threads
7420  * zip_method(in): compression method
7421  * zip_level(in): compression level
7422  * skip_activelog(in):
7423  * sleep_msecs(in):
7424  *
7425  */
7426 int
7427 logpb_backup (THREAD_ENTRY * thread_p, int num_perm_vols, const char *allbackup_path, FILEIO_BACKUP_LEVEL backup_level,
7428  bool delete_unneeded_logarchives, const char *backup_verbose_file_path, int num_threads,
7429  FILEIO_ZIP_METHOD zip_method, FILEIO_ZIP_LEVEL zip_level, int skip_activelog, int sleep_msecs,
7430  bool separate_keys)
7431 {
7432  FILEIO_BACKUP_SESSION session;
7433  const char *from_vlabel; /* Name of volume to backup (FROM) */
7434  char vol_backup[PATH_MAX]; /* Name of the backup volume (TO) */
7435 #if 0
7436  /* Not used */
7437  char real_pathbuf[PATH_MAX]; /* Real path */
7438 #endif
7439  VOLID volid; /* Current volume to backup */
7440  LOG_LSA bkup_start_lsa; /* Start point of backup */
7441  LOG_LSA chkpt_lsa; /* Checkpoint address where the backup process starts */
7442 #if defined(SERVER_MODE)
7443  LOG_PAGEID saved_run_nxchkpt_atpageid = NULL_PAGEID;
7444 #endif /* SERVER_MODE */
7445  FILE *backup_volinfo_fp = NULL; /* Pointer to backup information/directory file */
7446  const char *catmsg;
7447  const char *bk_vol; /* ptr to old bkup volume name */
7448  int unit_num;
7450  int first_arv_needed = -1; /* for self contained, consistent */
7451  int last_arv_needed = -1; /* backups, some arv are needed */
7452  bool beenwarned;
7453  bool isincremental = false; /* Assume full backups */
7454  bool bkup_in_progress = false;
7455 
7456  char mk_path[PATH_MAX] = { 0, };
7457  char separate_mk_path[PATH_MAX] = { 0, };
7458  char bkpath_without_units[PATH_MAX] = { 0, };
7459  const char *db_nopath_name_p;
7460  int keys_vdes = NULL_VOLDES;
7461 #if defined(SERVER_MODE)
7462  int rv;
7463  time_t wait_checkpoint_begin_time;
7464  bool print_backupdb_waiting_reason = false;
7465 #endif /* SERVER_MODE */
7466  int error_code = NO_ERROR;
7467  FILEIO_BACKUP_HEADER *io_bkup_hdr_p;
7468 
7469  time_t backup_start_time, backup_end_time;
7470  char old_bkpath[PATH_MAX];
7471  const char *str_tmp;
7472  time_t tmp_time;
7473  char time_val[CTIME_MAX];
7474 
7475  LOG_PAGEID vacuum_first_pageid = NULL_PAGEID;
7476 
7477 #if defined (SERVER_MODE)
7478  // check whether there is ongoing backup.
7479  LOG_CS_ENTER (thread_p);
7480  if (log_Gl.backup_in_progress == true)
7481  {
7482  LOG_CS_EXIT (thread_p);
7483  error_code = ER_LOG_BKUP_DUPLICATE_REQUESTS;
7484  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 0);
7485  return error_code;
7486  }
7487 
7488  log_Gl.backup_in_progress = true;
7489  LOG_CS_EXIT (thread_p);
7490 #endif /* SERVER_MODE */
7491 
7492  memset (&session, 0, sizeof (FILEIO_BACKUP_SESSION));
7493 
7494  /*
7495  * Determine the absolute path that corresponds with the desired location.
7496  */
7497  if (allbackup_path == NULL)
7498  {
7499  allbackup_path = log_Path;
7500  }
7501 #if 0
7502  /* Removed because it causes problems with deliberate symlinks, i.e. solaris tape device names. */
7503  else if (realpath (allbackup_path, real_pathbuf) != NULL)
7504  {
7505  allbackup_path = real_pathbuf;
7506  }
7507 #endif
7508 
7509  /* tde key file has to be mounted to access exclusively with TDE Utility if it exists */
7510  tde_make_keys_file_fullname (mk_path, log_Db_fullname, false);
7511  keys_vdes = fileio_mount (thread_p, log_Db_fullname, mk_path, LOG_DBTDE_KEYS_VOLID, 1, false);
7512  if (keys_vdes == NULL_VOLDES && fileio_is_volume_exist (mk_path))
7513  {
7514  ASSERT_ERROR ();
7515  error_code = er_errid ();
7516  goto error;
7517  }
7518 
7519  /* Initialization gives us some useful information about the backup location. */
7520  session.type = FILEIO_BACKUP_WRITE; /* access backup device for write */
7521  if (fileio_initialize_backup (log_Db_fullname, allbackup_path, &session, backup_level, backup_verbose_file_path,
7522  num_threads, sleep_msecs) == NULL)
7523  {
7524  error_code = ER_FAILED;
7525  goto error;
7526  }
7527 
7528  /*
7529  * Determine the first log archive that will be needed to insure
7530  * consistency if we are forced to restore the database with nothing but this backup.
7531  * first_arv_needed may need to be based on what archive chkpt_lsa is in.
7532  */
7533 
7534 #if defined (SERVER_MODE)
7535  print_backupdb_waiting_reason = false;
7536  wait_checkpoint_begin_time = time (NULL);
7537 loop:
7538 #endif /* SERVER_MODE */
7539 
7540  // actually, it is not really necessary for SA but just for code consistency.
7541  LOG_CS_ENTER (thread_p);
7542 
7543 #if defined (SERVER_MODE)
7544  /* check if checkpoint is in progress */
7546  {
7547  bool continue_check;
7548  LOG_CS_EXIT (thread_p);
7549  if (print_backupdb_waiting_reason == false && session.verbose_fp != NULL)
7550  {
7551  fprintf (session.verbose_fp, "[ Database backup will start after checkpointing is complete. ]\n\n");
7552  print_backupdb_waiting_reason = true;
7553  }
7554  /* wait until checkpoint process is finished */
7555 
7556  /* interrupt check */
7557  if (logtb_get_check_interrupt (thread_p) == true)
7558  {
7559  if (logtb_is_interrupted (thread_p, true, &continue_check) == true)
7560  {
7562  error_code = ER_INTERRUPTED;
7563  goto error;
7564  }
7565  }
7566 
7567  thread_sleep (1000); /* 1000 msec */
7568  goto loop;
7569  }
7570  if (print_backupdb_waiting_reason == true && session.verbose_fp != NULL)
7571  {
7572 
7573  fprintf (session.verbose_fp, "[ Database backup has been suspended for %lld seconds due to checkpoint. ]\n\n",
7574  (long long int) (time (NULL) - wait_checkpoint_begin_time));
7575  }
7576 
7577  /* block checkpoint process */
7578  saved_run_nxchkpt_atpageid = log_Gl.run_nxchkpt_atpageid;
7580 #endif /* SERVER_MODE */
7581 
7583  {
7584  first_arv_needed = log_Gl.hdr.last_arv_num_for_syscrashes;
7585  }
7586  else
7587  {
7588  first_arv_needed = log_Gl.hdr.nxarv_num;
7589  }
7590 
7591  vacuum_first_pageid = vacuum_min_log_pageid_to_keep (thread_p);
7592  vacuum_er_log (VACUUM_ER_LOG_ARCHIVES, "First log pageid in vacuum data is %lld\n", vacuum_first_pageid);
7593 
7594  if (vacuum_first_pageid != NULL_PAGEID && logpb_is_page_in_archive (vacuum_first_pageid))
7595  {
7596  int min_arv_required_for_vacuum = logpb_get_archive_number (thread_p, vacuum_first_pageid);
7597 
7598  vacuum_er_log (VACUUM_ER_LOG_ARCHIVES, "First archive number used for vacuum is %d\n",
7599  min_arv_required_for_vacuum);
7600 
7601  if (min_arv_required_for_vacuum >= 0)
7602  {
7603  if (first_arv_needed >= 0)
7604  {
7605  first_arv_needed = MIN (first_arv_needed, min_arv_required_for_vacuum);
7606  }
7607  else
7608  {
7609  first_arv_needed = min_arv_required_for_vacuum;
7610  }
7611  }
7612  else
7613  {
7614  /* Page should be in archive. */
7615  assert (false);
7616  }
7617 
7618  vacuum_er_log (VACUUM_ER_LOG_ARCHIVES, "First archive needed for backup is %d\n", first_arv_needed);
7619  }
7620 
7621  /* Get the current checkpoint address */
7622  rv = pthread_mutex_lock (&log_Gl.chkpt_lsa_lock);
7623  LSA_COPY (&chkpt_lsa, &log_Gl.hdr.chkpt_lsa);
7624  pthread_mutex_unlock (&log_Gl.chkpt_lsa_lock);
7625 
7626  LOG_CS_EXIT (thread_p);
7627 
7628  switch (backup_level)
7629  {
7630 
7632  /* Start at the lower level backup */
7634  {
7635  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_BACKUP_LEVEL_NOGAPS, 2, backup_level, backup_level - 1);
7637  error_code = ER_LOG_BACKUP_LEVEL_NOGAPS;
7638  goto error;
7639  }
7640  else
7641  {
7642  LSA_COPY (&bkup_start_lsa, &log_Gl.hdr.bkup_level0_lsa);
7643  }
7644  isincremental = true;
7645  break;
7646 
7648  /* Start at the lower level backup */
7650  {
7651  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_BACKUP_LEVEL_NOGAPS, 2, backup_level, backup_level - 1);
7653  error_code = ER_LOG_BACKUP_LEVEL_NOGAPS;
7654  goto error;
7655  }
7656  else
7657  {
7658  LSA_COPY (&bkup_start_lsa, &log_Gl.hdr.bkup_level1_lsa);
7659  }
7660  isincremental = true;
7661  break;
7662 
7663  default:
7665  /* Always start at -1|-1 */
7666  LSA_SET_NULL (&bkup_start_lsa);
7667  backup_level = FILEIO_BACKUP_FULL_LEVEL;
7668  break;
7669  }
7670 
7671  /*
7672  * Check for existing backup volumes in this location, and warn
7673  * the user that they will be destroyed.
7674  */
7676  {
7677  /* check for writable regular file */
7679  {
7681  error_code = ER_LOG_CREATE_DBBACKUP_DIRINFO;
7682  goto error;
7683  }
7684  /* check permission */
7685  if (access (log_Name_bkupinfo, W_OK) != 0)
7686  {
7687  error_code = ER_LOG_CANNOT_ACCESS_BACKUP;
7688  }
7689  backup_volinfo_fp = fopen (log_Name_bkupinfo, "r");
7690  if (error_code != NO_ERROR || backup_volinfo_fp == NULL)
7691  {
7694  goto error;
7695  }
7697  {
7700  fclose (backup_volinfo_fp);
7701  error_code = ER_LOG_CANNOT_ACCESS_BACKUP;
7702  goto error;
7703  }
7704  fclose (backup_volinfo_fp);
7705  }
7706 
7707  if (session.bkup.dtype != FILEIO_BACKUP_VOL_DEVICE)
7708  {
7709  /*
7710  * Delete previous backup volumes from this level. The first
7711  * loop tries to determine if indeed there will be anything to
7712  * unformat/delete, while the second loop does the actual deletions.
7713  * Deletion is done only if the backup is taking place
7714  * in the same location as the previous backup or
7715  * is the same path-name as the the previous backup.
7716  */
7717  beenwarned = false;
7718  unit_num = FILEIO_INITIAL_BACKUP_UNITS;
7719  bk_vol = fileio_get_backup_info_volume_name (backup_level, unit_num++, FILEIO_FIRST_BACKUP_VOL_INFO);
7720  while (bk_vol && !beenwarned)
7721  {
7722  if (fileio_is_volume_exist_and_file (bk_vol))
7723  {
7724  fileio_get_directory_path (old_bkpath, bk_vol);
7725  if (strcmp (old_bkpath, allbackup_path) == 0 || strcmp (bk_vol, allbackup_path) == 0)
7726  {
7727  if (!logpb_remote_ask_user_before_delete_volumes (thread_p, allbackup_path))
7728  {
7729  io_bkup_hdr_p = session.bkup.bkuphdr;
7730  tmp_time = (time_t) io_bkup_hdr_p->start_time;
7731  (void) ctime_r (&tmp_time, time_val);
7732  snprintf (old_bkpath, PATH_MAX,
7734  MSGCAT_LOG_BACKUP_HALTED_BY_USER), io_bkup_hdr_p->level,
7735  fileio_get_base_file_name (io_bkup_hdr_p->db_fullname), time_val,
7736  io_bkup_hdr_p->unit_num);
7738  -1, NULL, -1);
7740  error_code = ER_LOG_DBBACKUP_FAIL;
7741  goto error;
7742  }
7743  beenwarned = true;
7744  break;
7745  }
7746  } /* if (fileio_is_volume_exist_and_file(bk_vol)) */
7747  bk_vol = fileio_get_backup_info_volume_name (backup_level, unit_num++, FILEIO_FIRST_BACKUP_VOL_INFO);
7748  } /* while */
7749 
7750  /* try to delete the superceded backup volumes */
7751  if (beenwarned)
7752  {
7753  fileio_remove_all_backup (thread_p, backup_level);
7754  }
7755  }
7756 
7757  /* Throw away the old names and make room for new names */
7759 
7760  /*
7761  * Aside: all backup level related log hdr stuff should be in its own
7762  * array, including log_Gl (but I am hesitant to change it to avoid subtly
7763  * changing the disk rep). So for now, only have lower levels think array.
7764  * Arrays would allow future expansion to more than 3 levels.
7765  */
7766  LSA_COPY (&all_bkup_info[0].lsa, &log_Gl.hdr.bkup_level0_lsa);
7767  all_bkup_info[0].at_time = log_Gl.hdr.bkinfo[0].bkup_attime;
7768  LSA_COPY (&all_bkup_info[1].lsa, &log_Gl.hdr.bkup_level1_lsa);
7769  all_bkup_info[1].at_time = log_Gl.hdr.bkinfo[1].bkup_attime;
7770  LSA_COPY (&all_bkup_info[2].lsa, &log_Gl.hdr.bkup_level2_lsa);
7771  all_bkup_info[2].at_time = log_Gl.hdr.bkinfo[2].bkup_attime;
7772 
7773  if (session.verbose_fp)
7774  {
7775  if (backup_level != FILEIO_BACKUP_FULL_LEVEL)
7776  {
7777  fprintf (session.verbose_fp, "\n\n\n");
7778  }
7779 
7780  switch (backup_level)
7781  {
7783  str_tmp = "Full";
7784  break;
7786  str_tmp = "Incremental Level 1";
7787  break;
7788  default:
7790  str_tmp = "Incremental Level 2";
7791  break;
7792  }
7793  fprintf (session.verbose_fp, "[ Database(%s) %s Backup start ]\n\n", boot_db_name (), str_tmp);
7794 
7795  fprintf (session.verbose_fp, "- num-threads: %d\n\n", session.read_thread_info.num_threads);
7796 
7797  if (zip_method == FILEIO_ZIP_NONE_METHOD)
7798  {
7799  fprintf (session.verbose_fp, "- compression method: %s\n\n", fileio_get_zip_method_string (zip_method));
7800  }
7801  else
7802  {
7803  fprintf (session.verbose_fp, "- compression method: %d (%s), compression level: %d (%s)\n\n", zip_method,
7804  fileio_get_zip_method_string (zip_method), zip_level, fileio_get_zip_level_string (zip_level));
7805  }
7806 
7807  if (skip_activelog)
7808  {
7809  // unreachable. skip_activelog option is obsoleted.
7810  assert (!skip_activelog);
7811  fprintf (session.verbose_fp, "- not include active log.\n\n");
7812  }
7813 
7814 #if defined(SERVER_MODE)
7815  if (sleep_msecs > 0 || prm_get_integer_value (PRM_ID_IO_BACKUP_SLEEP_MSECS) > 0)
7816  {
7817  int sleep_nsecs;
7818 
7819  if (sleep_msecs > 0) /* priority 1 */
7820  {
7821  sleep_nsecs = sleep_msecs * 1000;
7822  }
7823  else if (prm_get_integer_value (PRM_ID_IO_BACKUP_SLEEP_MSECS) > 0) /* priority 2 */
7824  {
7825  sleep_nsecs = prm_get_integer_value (PRM_ID_IO_BACKUP_SLEEP_MSECS) * 1000;
7826  }
7827  else
7828  {
7829  sleep_nsecs = 0;
7830  }
7831 
7832  if (sleep_nsecs > 0)
7833  {
7834  fprintf (session.verbose_fp, "- sleep %d millisecond per 1M read.\n\n", sleep_nsecs / 1000);
7835  }
7836  }
7837 #endif
7838 
7839  backup_start_time = time (NULL);
7840  (void) ctime_r (&backup_start_time, time_val);
7841  fprintf (session.verbose_fp, "- backup start time: %s\n", time_val);
7842  fprintf (session.verbose_fp, "- number of permanent volumes: %d\n\n", num_perm_vols);
7843 
7844  fprintf (session.verbose_fp, "- HA apply info: %s %lld %lld %d\n\n", log_Gl.hdr.prefix_name,
7845  (long long int) log_Gl.hdr.db_creation, (long long int) log_Gl.hdr.smallest_lsa_at_last_chkpt.pageid,
7847 
7848  fprintf (session.verbose_fp, "- backup progress status\n\n");
7849  fprintf (session.verbose_fp, "-----------------------------------------------------------------------------\n");
7850  fprintf (session.verbose_fp, " volume name | # of pages | backup progress status | done \n");
7851  fprintf (session.verbose_fp, "-----------------------------------------------------------------------------\n");
7852  }
7853 
7854  /* Begin backing up in earnest */
7855  assert (!skip_activelog);
7856  session.bkup.bkuphdr->skip_activelog = skip_activelog;
7857 
7858  if (fileio_start_backup (thread_p, log_Db_fullname, &log_Gl.hdr.db_creation, backup_level, &bkup_start_lsa,
7859  &chkpt_lsa, all_bkup_info, &session, zip_method, zip_level) == NULL)
7860  {
7861  error_code = ER_FAILED;
7862  goto error;
7863  }
7864 
7865  if (separate_keys)
7866  {
7867  db_nopath_name_p = fileio_get_base_file_name (log_Db_fullname);
7868  fileio_make_backup_name (bkpath_without_units, db_nopath_name_p, session.bkup.current_path, backup_level,
7870  tde_make_keys_file_fullname (separate_mk_path, bkpath_without_units, true);
7871  /* Keep mounting mk file to be exclusive with other tools */
7872  error_code = tde_copy_keys_file (thread_p, separate_mk_path, mk_path, false, true);
7873  if (error_code != NO_ERROR)
7874  {
7875  goto error;
7876  }
7877  }
7878 
7879  /* Backup every volume */
7880  volid = LOG_DBTDE_KEYS_VOLID;
7881  do
7882  {
7883  switch (volid)
7884  {
7885  case LOG_DBTDE_KEYS_VOLID:
7886  if (separate_keys)
7887  {
7888  /* already backuped up as a separate file */
7889  volid++;
7890  continue;
7891  }
7892  else
7893  {
7894  from_vlabel = mk_path;
7895  }
7896  break;
7897  case LOG_DBVOLINFO_VOLID:
7899  from_vlabel = vol_backup;
7900  break;
7901  case LOG_DBLOG_INFO_VOLID:
7903  /*
7904  * These information volumes are backed-up at the very end.
7905  */
7906  volid++;
7907  continue;
7909  /*
7910  * Archiving log active must be done after all data volumes
7911  * have been backed up (in order to insure we get all of the
7912  * log records needed to restore consistency).
7913  */
7914  volid = LOG_DBFIRST_VOLID;
7915  continue;
7916  default:
7917  from_vlabel = fileio_get_volume_label (volid, PEEK);
7918  break;
7919  }
7920 
7921  if (volid >= LOG_DBFIRST_VOLID)
7922  {
7923  error_code = logpb_backup_for_volume (thread_p, volid, &chkpt_lsa, &session, isincremental);
7924  if (error_code != NO_ERROR)
7925  {
7926  goto error;
7927  }
7928  disk_lock_extend ();
7929  volid = fileio_find_next_perm_volume (thread_p, volid);
7930  disk_unlock_extend ();
7931  }
7932  else
7933  {
7934  error_code = fileio_backup_volume (thread_p, &session, from_vlabel, volid, -1, false);
7935  if (error_code != NO_ERROR)
7936  {
7937  /* keys file can be omitted */
7938  if (volid != LOG_DBTDE_KEYS_VOLID)
7939  {
7940  goto error;
7941  }
7942  }
7943  volid++;
7944  }
7945  /* in case an error occurs, we must destroy our partial backup */
7946  bkup_in_progress = true;
7947  }
7948  while (volid != NULL_VOLID);
7949 
7950 #if defined(SERVER_MODE)
7951  /*
7952  * Only when in client/server, we may need to force an archive
7953  * of the current log active if there were any active transactions
7954  * before or during the backup.
7955  * This is to insure we have enough log records to restore consistency
7956  * to the database in the event a restore with no other log archives
7957  * is needed.
7958  */
7959  LOG_CS_ENTER (thread_p);
7961  {
7962  logpb_archive_active_log (thread_p);
7963  }
7964 
7965  last_arv_needed = log_Gl.hdr.nxarv_num - 1;
7966  LOG_CS_EXIT (thread_p);
7967 
7968  if (last_arv_needed >= first_arv_needed)
7969  {
7970  error_code = logpb_backup_needed_archive_logs (thread_p, &session, first_arv_needed, last_arv_needed);
7971  if (error_code != NO_ERROR)
7972  {
7973  goto error;
7974  }
7975  }
7976 #else /* SERVER_MODE */
7977  /*
7978  * In stand-alone, there can be no other activity modifying the log
7979  * so we do not have to keep any log records to be consistent.
7980  */
7981  first_arv_needed = -1;
7982  last_arv_needed = -1;
7983 #endif /* SERVER_MODE */
7984 
7985  /* at here, diable multi-thread usage for fast Log copy */
7986  session.read_thread_info.num_threads = 1;
7987 
7989 
7990  LOG_CS_ENTER (thread_p);
7991 
7992 #if defined(SERVER_MODE)
7993 
7994  if (last_arv_needed < log_Gl.hdr.nxarv_num - 1)
7995  {
7996  error_code = logpb_backup_needed_archive_logs (thread_p, &session, last_arv_needed + 1, log_Gl.hdr.nxarv_num - 1);
7997  if (error_code != NO_ERROR)
7998  {
7999  LOG_CS_EXIT (thread_p);
8001  goto error;
8002  }
8003 
8004  last_arv_needed = log_Gl.hdr.nxarv_num - 1;
8005  }
8006 #endif
8007 
8008  if (fileio_is_volume_exist (log_Name_info) == true)
8009  {
8010  error_code = fileio_backup_volume (thread_p, &session, log_Name_info, LOG_DBLOG_INFO_VOLID, -1, false);
8011  if (error_code != NO_ERROR)
8012  {
8013  LOG_CS_EXIT (thread_p);
8015  goto error;
8016  }
8017  }
8018 
8019  /*
8020  * We must store the final bkvinf file at the very end of the backup
8021  * to have the best chance of having all of the information in it.
8022  * Note: that there is a window that the last bkvinf entry still not being
8023  * there if a new backup volume is needed while writing this volume.
8024  * However, in this case, then restore will ask the user for the
8025  * subsequent backup unit num.
8026  */
8028  if (error_code != NO_ERROR)
8029  {
8030  LOG_CS_EXIT (thread_p);
8032  goto error;
8033  }
8034 
8035  /* Clear log header information regarding previous backups */
8037 
8038  /* Save additional info and metrics from this backup */
8039  log_Gl.hdr.bkinfo[backup_level].bkup_attime = session.bkup.bkuphdr->start_time;
8040 
8041  switch (backup_level)
8042  {
8044  default:
8045  LSA_COPY (&log_Gl.hdr.bkup_level0_lsa, &chkpt_lsa);
8050  break;
8051 
8053  LSA_COPY (&log_Gl.hdr.bkup_level1_lsa, &chkpt_lsa);
8056  break;
8057 
8059  LSA_COPY (&log_Gl.hdr.bkup_level2_lsa, &chkpt_lsa);
8060  break;
8061  }
8062 
8063  /* Now indicate how many volumes were backed up */
8064  logpb_flush_header (thread_p);
8065 
8066  /* Include active log always. Skipping log active is obsolete. */
8067  error_code = fileio_backup_volume (thread_p, &session, log_Name_active, LOG_DBLOG_ACTIVE_VOLID, -1, false);
8068  if (error_code != NO_ERROR)
8069  {
8070  LOG_CS_EXIT (thread_p);
8072  goto error;
8073  }
8074 
8075  if (fileio_finish_backup (thread_p, &session) == NULL)
8076  {
8077  LOG_CS_EXIT (thread_p);
8079  error_code = ER_FAILED;
8080  goto error;
8081  }
8082 
8083  if (delete_unneeded_logarchives != false)
8084  {
8086  if (catmsg)
8087  {
8088  logpb_remove_archive_logs (thread_p, catmsg);
8089  }
8090  }
8091 
8092  LOG_CS_EXIT (thread_p);
8093 
8095 
8097  if (error_code != NO_ERROR)
8098  {
8099  goto error;
8100  }
8101 
8102  if (session.verbose_fp)
8103  {
8104  fprintf (session.verbose_fp, "-----------------------------------------------------------------------------\n\n");
8105  backup_end_time = time (NULL);
8106  (void) ctime_r (&backup_end_time, time_val);
8107  fprintf (session.verbose_fp, "# backup end time: %s\n", time_val);
8108  switch (backup_level)
8109  {
8111  str_tmp = "Full";
8112  break;
8114  str_tmp = "Incremental Level 1";
8115  break;
8116  default:
8118  str_tmp = "Incremental Level 2";
8119  break;
8120  }
8121  fprintf (session.verbose_fp, "[ Database(%s) %s Backup end ]\n", boot_db_name (), str_tmp);
8122  }
8123 
8124  fileio_abort_backup (thread_p, &session, false);
8125 
8126 #if defined(SERVER_MODE)
8127  LOG_CS_ENTER (thread_p);
8128  log_Gl.run_nxchkpt_atpageid = saved_run_nxchkpt_atpageid;
8129  log_Gl.backup_in_progress = false;
8130  LOG_CS_EXIT (thread_p);
8131 #endif /* SERVER_MODE */
8132 
8133  if (keys_vdes != NULL_VOLDES)
8134  {
8135  fileio_dismount (thread_p, keys_vdes);
8136  }
8137 
8138  return NO_ERROR;
8139 
8140  /* ********* */
8141 error:
8142 
8143  /*
8144  * Destroy the backup that has been created.
8145  */
8146  fileio_abort_backup (thread_p, &session, bkup_in_progress);
8147 
8148 #if defined(SERVER_MODE)
8149  LOG_CS_ENTER (thread_p);
8150  if (saved_run_nxchkpt_atpageid != NULL_PAGEID)
8151  {
8152  log_Gl.run_nxchkpt_atpageid = saved_run_nxchkpt_atpageid;
8153  }
8154  log_Gl.backup_in_progress = false;
8155  LOG_CS_EXIT (thread_p);
8156 #endif /* SERVER_MODE */
8157 
8158  if (keys_vdes != NULL_VOLDES)
8159  {
8160  fileio_dismount (thread_p, keys_vdes);
8161  }
8162 
8163  return error_code;
8164 }
8165 
8166 /*
8167  * log_update_backup_volinfo - UPDATE DISK VERSION OF BKUP VOLINFO FILE
8168  *
8169  * return: NO_ERROR if all OK, ER status otherwise
8170  *
8171  * bkupinfo_file_name(in): file name to write info to
8172  *
8173  * NOTE: Save the in-memory cache of backup volume names to a file.
8174  */
8175 static int
8176 logpb_update_backup_volume_info (const char *bkupinfo_file_name)
8177 {
8178  FILE *backup_volinfo_fp;
8179  int error_code = NO_ERROR;
8180 
8181  backup_volinfo_fp = fopen (bkupinfo_file_name, "w");
8182  if (backup_volinfo_fp == NULL)
8183  {
8185  error_code = ER_LOG_CREATE_DBBACKUP_DIRINFO;
8186  return error_code;
8187  }
8188 
8189  /*
8190  * If an error occurs while writing, should allow the user to try again.
8191  */
8192  error_code = fileio_write_backup_info_entries (backup_volinfo_fp, FILEIO_FIRST_BACKUP_VOL_INFO);
8193  if (error_code != NO_ERROR)
8194  {
8196  fclose (backup_volinfo_fp);
8197  return error_code;
8198  }
8199  fflush (backup_volinfo_fp);
8200  fclose (backup_volinfo_fp);
8201 
8202  return error_code;
8203 }
8204 
8205 /*
8206  * logpb_check_stop_at_time - Check if the stopat time is valid
8207  *
8208  * return: NO_ERROR if valid, ER_FAILED otherwise
8209  *
8210  * session(in):
8211  * stop_at(in):
8212  * backup_time(in):
8213  */
8214 static int
8215 logpb_check_stop_at_time (FILEIO_BACKUP_SESSION * session, time_t stop_at, time_t backup_time)
8216 {
8217  char ctime_buf1[CTIME_MAX], ctime_buf2[CTIME_MAX];
8218  size_t time_str_len;
8219 
8220  if (stop_at < backup_time)
8221  {
8222  ctime_r (&stop_at, ctime_buf1);
8223  ctime_r (&backup_time, ctime_buf2);
8224 
8225  /* strip '\n' */
8226  time_str_len = strlen (ctime_buf1);
8227  if (time_str_len > 0)
8228  {
8229  ctime_buf1[time_str_len - 1] = 0;
8230  }
8231  time_str_len = strlen (ctime_buf2);
8232  if (time_str_len > 0)
8233  {
8234  ctime_buf2[time_str_len - 1] = 0;
8235  }
8236 
8237  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_UPTODATE_ERROR, 2, ctime_buf1, ctime_buf2);
8238 
8239  return ER_LOG_UPTODATE_ERROR;
8240  }
8241 
8242  return NO_ERROR;
8243 }
8244 
8245 /*
8246  * logpb_restore - Restore volume from its backup
8247  *
8248  * return: NO_ERROR if all OK, ER status otherwise
8249  *
8250  * db_fullname(in): Full name of the database
8251  * logpath(in): Directory where the log volumes reside
8252  * prefix_logname(in):
8253  * newall_path(in):
8254  * ask_forpath(in):
8255  * r_args(in):
8256  *
8257  * NOTE:Restore a database from its backup files. This function is run
8258  * without recovery. The logs must be applied to the restored
8259  * volume to finish the full restore process. This is not done
8260  * here since the database may have other volumes to restore.
8261  * We must lock the active log during the restore to keep other
8262  * utilities from trying to use the db files being restored.
8263  * This routine leaves the database locked, as there will
8264  * probably be a restart following the restore.
8265  *
8266  * This function must be run offline.
8267  *
8268  * Note this function is incomplete.. How to change location of files
8269  * during restore... The main problem here is the VOLINFO which has to
8270  * be recreated without updating the header of the volumes.
8271  */
8272 int
8273 logpb_restore (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname,
8274  bo_restart_arg * r_args)
8275 {
8276  FILEIO_BACKUP_SESSION session_storage;
8277  FILEIO_BACKUP_SESSION *session = NULL;
8278  const char *nopath_name; /* Name without path */
8279  char to_volname[PATH_MAX]; /* Name of a volume (TO) */
8280  char verbose_to_volname[PATH_MAX]; /* Printable name of a volume (TO) */
8281  char prev_volname[PATH_MAX]; /* Name of a prev volume (TO) */
8282  char from_volbackup[PATH_MAX]; /* Name of the backup volume (FROM) */
8283  VOLID to_volid;
8284  FILE *backup_volinfo_fp = NULL; /* Pointer to backup information/directory file */
8285  int another_vol;
8286  INT64 db_creation;
8287  INT64 bkup_match_time = 0;
8288  PGLENGTH db_iopagesize;
8289  PGLENGTH log_page_size;
8290  float db_compatibility;
8291  PGLENGTH bkdb_iopagesize;
8292  float bkdb_compatibility;
8293 
8296  DKNPAGES total_pages;
8297 
8298  FILEIO_BACKUP_LEVEL try_level, start_level;
8299  bool first_time = true;
8300  bool remember_pages = false;
8301  bool error_expected = false;
8302  bool restore_in_progress = false; /* true if any vols restored */
8303  int lgat_vdes = NULL_VOLDES;
8304  time_t restore_start_time, restore_end_time;
8305  char time_val[CTIME_MAX];
8306  int loop_cnt = 0;
8307  char tmp_logfiles_from_backup[PATH_MAX];
8308  char bk_mk_path[PATH_MAX];
8309  char bkpath_without_units[PATH_MAX];
8310  char backup_dir_path[PATH_MAX];
8311  char *volume_name_p;
8312  struct stat stat_buf;
8313  int error_code = NO_ERROR, success = NO_ERROR;
8314  bool printtoc;
8315  INT64 backup_time;
8316  REL_COMPATIBILITY compat;
8317  int dummy;
8318 
8319  try_level = (FILEIO_BACKUP_LEVEL) r_args->level;
8320  start_level = try_level;
8321 
8322  memset (&session_storage, 0, sizeof (FILEIO_BACKUP_SESSION));
8323  memset (verbose_to_volname, 0, PATH_MAX);
8324  memset (tmp_logfiles_from_backup, 0, PATH_MAX);
8325 
8326  LOG_CS_ENTER (thread_p);
8327 
8328  if (logpb_find_header_parameters (thread_p, true, db_fullname, logpath, prefix_logname, &db_iopagesize,
8329  &log_page_size, &db_creation, &db_compatibility, &dummy) == -1)
8330  {
8331  db_iopagesize = IO_PAGESIZE;
8332  log_page_size = LOG_PAGESIZE;
8333  db_creation = 0;
8334  db_compatibility = rel_disk_compatible ();
8335  }
8336 
8337  fileio_page_bitmap_list_init (&page_bitmap_list);
8338 
8339  /*
8340  * Must lock the database if possible. Would be nice to have a way
8341  * to lock the db somehow even when the lgat file does not exist.
8342  */
8344  {
8345  lgat_vdes = fileio_mount (thread_p, db_fullname, log_Name_active, LOG_DBLOG_ACTIVE_VOLID, true, false);
8346  if (lgat_vdes == NULL_VOLDES)
8347  {
8348  error_code = ER_FAILED;
8349  LOG_CS_EXIT (thread_p);
8350  goto error;
8351  }
8352  }
8353 
8354  nopath_name = fileio_get_base_file_name (db_fullname);
8355 
8356  /* The enum type can be negative in Windows. */
8357  while (success == NO_ERROR && try_level >= FILEIO_BACKUP_FULL_LEVEL && try_level < FILEIO_BACKUP_UNDEFINED_LEVEL)
8358  {
8359  if (!first_time)
8360  {
8361  /* Prepare to reread bkvinf file restored by higher level */
8363 
8364  /* Have to match timestamps of lower levels when restoring */
8365  bkup_match_time = session->bkup.bkuphdr->previnfo[try_level].at_time;
8366 
8367  /* Clean up previous restore of higher level */
8368  if (fileio_finish_restore (thread_p, session) == NO_ERROR)
8369  {
8370  success = NO_ERROR;
8371  }
8372  else
8373  {
8374  success = ER_FAILED;
8375  }
8376 
8377  assert (try_level != (FILEIO_BACKUP_LEVEL) r_args->level);
8378  }
8379 
8380  error_code =
8381  fileio_get_backup_volume (thread_p, db_fullname, logpath, r_args->backuppath, try_level, from_volbackup);
8382  if (error_code == ER_LOG_CANNOT_ACCESS_BACKUP)
8383  {
8384  error_expected = true;
8385  LOG_CS_EXIT (thread_p);
8386  goto error;
8387  }
8388  else if (error_code != NO_ERROR)
8389  {
8390  LOG_CS_EXIT (thread_p);
8391  goto error;
8392  }
8393 
8394  printtoc = (r_args->printtoc) ? false : true;
8395  if (fileio_start_restore (thread_p, db_fullname, from_volbackup, db_creation, &bkdb_iopagesize,
8396  &bkdb_compatibility, &session_storage, try_level, printtoc, bkup_match_time,
8397  r_args->verbose_file, r_args->newvolpath) == NULL)
8398  {
8399  /* Cannot access backup file.. Restore from backup is cancelled */
8400  if (er_errid () == ER_GENERIC_ERROR)
8401  {
8403  }
8404  error_code = ER_LOG_CANNOT_ACCESS_BACKUP;
8405  LOG_CS_EXIT (thread_p);
8406  goto error;
8407  }
8408 
8409  memset (session_storage.bkup.log_path, 0, PATH_MAX);
8410  strncpy_bufsize (session_storage.bkup.log_path, logpath);
8411 
8412  session = &session_storage;
8413 
8414  if (first_time)
8415  {
8416  if (r_args->restore_upto_bktime)
8417  {
8418  r_args->stopat = (time_t) session->bkup.bkuphdr->end_time;
8419  }
8420  else if (r_args->stopat > 0)
8421  {
8422  if (session->bkup.bkuphdr->end_time > 0)
8423  {
8424  backup_time = session->bkup.bkuphdr->end_time;
8425  }
8426  else
8427  {
8428  backup_time = session->bkup.bkuphdr->start_time;
8429  }
8430  error_code = logpb_check_stop_at_time (session, r_args->stopat, (time_t) backup_time);
8431  if (error_code != NO_ERROR)
8432  {
8433  LOG_CS_EXIT (thread_p);
8434  error_expected = true;
8435  goto error;
8436  }
8437  }
8438  }
8439 
8440  if (first_time && db_iopagesize != bkdb_iopagesize)
8441  {
8442  /*
8443  * Pagesize is incorrect. We need to undefine anything that has been
8444  * created with old pagesize and start again.
8445  * If we do not have a log, we should reset the pagesize and start the
8446  * restore process.
8447  */
8448  if (log_Gl.append.vdes == NULL_VOLDES)
8449  {
8450  /*
8451  * Reset the page size
8452  */
8453  if (db_set_page_size (bkdb_iopagesize, log_page_size) != NO_ERROR)
8454  {
8455  error_code = ER_FAILED;
8456  LOG_CS_EXIT (thread_p);
8457  goto error;
8458  }
8459 
8460  error_code = logtb_define_trantable_log_latch (thread_p, -1);
8461  if (error_code != NO_ERROR)
8462  {
8463  LOG_CS_EXIT (thread_p);
8464  goto error;
8465  }
8466  }
8467  }
8468 
8469  /* Can this be moved to restore_continue? */
8470  /* Removed strict condition for checking disk compatibility. Check it according to the predefined rules. */
8471  compat = rel_get_disk_compatible (bkdb_compatibility, NULL);
8472  if (compat != REL_FULLY_COMPATIBLE && compat != REL_BACKWARD_COMPATIBLE)
8473  {
8474  /* Database is incompatible with current release */
8476  rel_release_string ());
8477  error_code = ER_LOG_BKUP_INCOMPATIBLE;
8478  LOG_CS_EXIT (thread_p);
8479  goto error;
8480  }
8481 
8482  if (session->verbose_fp)
8483  {
8484  if (first_time)
8485  {
8486  fprintf (session->verbose_fp, "\n[ Database(%s) Restore (level = %d) start ]\n\n", boot_db_name (),
8487  r_args->level);
8488 
8489  restore_start_time = time (NULL);
8490  (void) ctime_r (&restore_start_time, time_val);
8491  fprintf (session->verbose_fp, "- restore start time: %s\n", time_val);
8492  fprintf (session->verbose_fp, "- restore steps: %d \n", r_args->level + 1);
8493  }
8494 
8495  fprintf (session->verbose_fp, " step %1d) restore using (level = %d) backup data\n", ++loop_cnt, try_level);
8496  fprintf (session->verbose_fp, "\n");
8497 
8498  fprintf (session->verbose_fp, "- restore progress status (using level = %d backup data)\n", try_level);
8499  fprintf (session->verbose_fp,
8500  " -----------------------------------------------------------------------------\n");
8501  fprintf (session->verbose_fp,
8502  " volume name | # of pages | restore progress status | done \n");
8503  fprintf (session->verbose_fp,
8504  " -----------------------------------------------------------------------------\n");
8505  }
8506 
8507  /* add new bkvinf entry into cache data */
8508  fileio_add_volume_to_backup_info (session->bkup.vlabel, try_level, session->bkup.bkuphdr->unit_num,
8510 
8511  if (first_time)
8512  {
8513  LSA_COPY (&session->bkup.last_chkpt_lsa, &session->bkup.bkuphdr->chkpt_lsa);
8514 
8515  /*
8516  * The tde key file (_keys) which is going to be used during restart
8517  * is the thing in the first time (the highest level).
8518  */
8519 
8520  /* If backup path is not a directory, extract backup key file on the directory that contains the backup path */
8521  if (stat (session->bkup.current_path, &stat_buf) != 0)
8522  {
8524  session->bkup.current_path);
8525  error_code = ER_LOG_CANNOT_ACCESS_BACKUP;
8526  LOG_CS_EXIT (thread_p);
8527  goto error;
8528  }
8529  else if (S_ISDIR (stat_buf.st_mode))
8530  {
8531  memcpy (backup_dir_path, session->bkup.current_path, PATH_MAX);
8532  }
8533  else
8534  {
8535  /* it might be pipe, and others like raw device is not tested */
8536  fileio_get_directory_path (backup_dir_path, session->bkup.current_path);
8537  }
8538 
8539  fileio_make_backup_name (bkpath_without_units, nopath_name, backup_dir_path,
8541  tde_make_keys_file_fullname (bk_mk_path, bkpath_without_units, true);
8542  if (r_args->keys_file_path[0] == '\0') /* the path given by user is prioritized */
8543  {
8544  memcpy (r_args->keys_file_path, bk_mk_path, PATH_MAX);
8545  }
8546  else
8547  {
8548  /* If the keys file is given, check if it is valid. */
8549  int vdes =
8550  fileio_mount (thread_p, boot_db_full_name (), r_args->keys_file_path, LOG_DBTDE_KEYS_VOLID, false,
8551  false);
8552  if (vdes == NULL_VOLDES)
8553  {
8554  ASSERT_ERROR_AND_SET (error_code);
8555  LOG_CS_EXIT (thread_p);
8556  error_expected = true;
8557  goto error;
8558  }
8559 
8560  if (tde_validate_keys_file (vdes) == false)
8561  {
8563  error_code = ER_TDE_INVALID_KEYS_FILE;
8564  fileio_dismount (thread_p, vdes);
8565  LOG_CS_EXIT (thread_p);
8566  error_expected = true;
8567  goto error;
8568  }
8569 
8570  fileio_dismount (thread_p, vdes);
8571  }
8572  }
8573 
8574  while (success == NO_ERROR)
8575  {
8576  another_vol = fileio_get_next_restore_file (thread_p, session, to_volname, &to_volid);
8577  if (another_vol == 1)
8578  {
8579  if (session->verbose_fp)
8580  {
8581  strcpy (verbose_to_volname, to_volname);
8582  }
8583 
8584  if (to_volid == LOG_DBLOG_ACTIVE_VOLID || to_volid == LOG_DBLOG_INFO_VOLID
8585  || to_volid == LOG_DBLOG_ARCHIVE_VOLID)
8586  {
8587  /* rename _lgat to _lgat_tmp name */
8588  fileio_make_temp_log_files_from_backup (tmp_logfiles_from_backup, to_volid,
8589  (FILEIO_BACKUP_LEVEL) r_args->level, to_volname);
8590  volume_name_p = tmp_logfiles_from_backup;
8591  }
8592  else if (to_volid == LOG_DBTDE_KEYS_VOLID)
8593  {
8594  /* backup mk file is extracted on the backup volume path */
8595  volume_name_p = bk_mk_path;
8596  }
8597  else
8598  {
8599  volume_name_p = to_volname;
8600  }
8601 
8602  restore_in_progress = true;
8603  if (start_level > FILEIO_BACKUP_FULL_LEVEL)
8604  {
8605  remember_pages = true;
8606  }
8607 
8608  /*
8609  * Another volume/file to restore
8610  */
8611  switch (to_volid)
8612  {
8615  case LOG_DBLOG_INFO_VOLID:
8616  case LOG_DBVOLINFO_VOLID:
8618  case LOG_DBTDE_KEYS_VOLID:
8619 
8620  /* We can only take the most recent information, and we do not want to overwrite it with out of data
8621  * information from earlier backups. This is because we are applying the restoration in reverse time
8622  * order. */
8623  if (!first_time)
8624  {
8625  /* Need to skip over this volume in the backup */
8626  success = fileio_skip_restore_volume (thread_p, session);
8627  if (success != NO_ERROR)
8628  {
8629  success = ER_FAILED;
8630  error_code = ER_FAILED;
8631  LOG_CS_EXIT (thread_p);
8632  goto error;
8633  }
8634  else
8635  {
8636  success = NO_ERROR;
8637  continue;
8638  }
8639  }
8640  break;
8641 
8642  default:
8643  break;
8644  }
8645 
8646  /* we need to tell fileio_restore_volume to avoid tracking the pages for some volids. */
8647  if (to_volid < LOG_DBFIRST_VOLID)
8648  {
8649  remember_pages = false;
8650  }
8651  else
8652  {
8653  total_pages = (DKNPAGES) CEIL_PTVDIV (session->dbfile.nbytes, IO_PAGESIZE);
8654  /*
8655  * Create a page_bitmap to remember the id's of pages
8656  * that have been written. We only need to write the page
8657  * (once) from the most recent backup.
8658  */
8659  page_bitmap = fileio_page_bitmap_list_find (&page_bitmap_list, to_volid);
8660  if (page_bitmap == NULL)
8661  {
8662  page_bitmap = fileio_page_bitmap_create (to_volid, total_pages);
8663  if (page_bitmap == NULL)
8664  {
8665  goto error;
8666  }
8667  fileio_page_bitmap_list_add (&page_bitmap_list, page_bitmap);
8668  }
8669  }
8670 
8671  success =
8672  fileio_restore_volume (thread_p, session, volume_name_p, verbose_to_volname, prev_volname, page_bitmap,
8673  remember_pages);
8674 
8675  if (success != NO_ERROR)
8676  {
8677  break;
8678  }
8679 
8680  if (volume_name_p == tmp_logfiles_from_backup)
8681  {
8682  // when an archive exists, always respect it.
8683  // when the active exists and the next archive of it does not, use it to restore.
8684  bool is_backup_log_useful = false;
8685 
8686  if (stat (to_volname, &stat_buf) != 0 && stat (tmp_logfiles_from_backup, &stat_buf) == 0)
8687  {
8688  is_backup_log_useful = true;
8689 
8690  if (to_volid == LOG_DBLOG_ACTIVE_VOLID
8691  && !logpb_is_log_active_from_backup_useful (thread_p, tmp_logfiles_from_backup, db_fullname))
8692  {
8693  // log active from backup is useless since it is older than the available log archives
8694  is_backup_log_useful = false;
8695  }
8696  }
8697 
8698  if (is_backup_log_useful)
8699  {
8700  if (to_volid == LOG_DBLOG_ACTIVE_VOLID && lgat_vdes != NULL_VOLDES)
8701  {
8702  fileio_dismount (thread_p, lgat_vdes);
8703  lgat_vdes = NULL_VOLDES;
8704  }
8705 
8706  os_rename_file (tmp_logfiles_from_backup, to_volname);
8707  }
8708  else
8709  {
8710  unlink (tmp_logfiles_from_backup);
8711  }
8712 
8713  tmp_logfiles_from_backup[0] = '\0';
8714  }
8715 
8716  volume_name_p = NULL;
8717  }
8718  else if (another_vol == 0)
8719  {
8720  break;
8721  }
8722  else
8723  {
8724  success = ER_FAILED;
8725  break;
8726  }
8727  }
8728 
8729  /* if the device type is FILEIO_BACKUP_VOL_DEVICE, the end time of backup is loaded during the last
8730  * fileio_get_next_restore_file() call, so we must check if the stopat time is valid. */
8731  if (first_time && session->bkup.dtype == FILEIO_BACKUP_VOL_DEVICE)
8732  {
8733  if (r_args->restore_upto_bktime)
8734  {
8735  r_args->stopat = (time_t) session->bkup.bkuphdr->end_time;
8736  }
8737  else if (r_args->stopat > 0)
8738  {
8739  error_code = logpb_check_stop_at_time (session, r_args->stopat, (time_t) session->bkup.bkuphdr->end_time);
8740  if (error_code != NO_ERROR)
8741  {
8742  LOG_CS_EXIT (thread_p);
8743  error_expected = true;
8744  goto error;
8745  }
8746  }
8747  }
8748 
8749  first_time = false;
8750 
8751  if (session->verbose_fp)
8752  {
8753  fprintf (session->verbose_fp,
8754  " -----------------------------------------------------------------------------\n\n");
8755  }
8756 
8757  try_level = (FILEIO_BACKUP_LEVEL) (try_level - 1);
8758  }
8759 
8760  /* make bkvinf file */
8761  fileio_make_backup_volume_info_name (from_volbackup, logpath, nopath_name);
8762  backup_volinfo_fp = fopen (from_volbackup, "w");
8763  if (backup_volinfo_fp != NULL)
8764  {
8766  fclose (backup_volinfo_fp);
8767  }
8768 
8769  if (session != NULL)
8770  {
8771  if (session->verbose_fp)
8772  {
8773  restore_end_time = time (NULL);
8774  (void) ctime_r (&restore_end_time, time_val);
8775  fprintf (session->verbose_fp, "- restore end time: %s\n", time_val);
8776  fprintf (session->verbose_fp, "[ Database(%s) Restore (level = %d) end ]\n", boot_db_name (), r_args->level);
8777  }
8778 
8779  if (fileio_finish_restore (thread_p, session) == NO_ERROR)
8780  {
8781  error_code = NO_ERROR;
8782  }
8783  else
8784  {
8785  error_code = ER_FAILED;
8786  }
8787  }
8788 
8789  LOG_CS_EXIT (thread_p);
8790 
8791  fileio_page_bitmap_list_destroy (&page_bitmap_list);
8792 
8794 
8795  if (success != NO_ERROR)
8796  {
8797  return success;
8798  }
8799  else
8800  {
8801  return error_code;
8802  }
8803 
8804  /* **** */
8805 error:
8806  if (restore_in_progress)
8807  {
8808  /*
8809  * We have probably already restored something to their database
8810  * and therefore they need to be sure and try another restore until
8811  * they succeed.
8812  */
8814  session->bkup.name,
8815  ((session->bkup.bkuphdr == NULL) ? FILEIO_INITIAL_BACKUP_UNITS : session->bkup.bkuphdr->unit_num),
8816  to_volname, session->dbfile.volid);
8817 
8819  error_code = ER_LOG_MAYNEED_MEDIA_RECOVERY;
8820  }
8821 
8822  if (backup_volinfo_fp != NULL)
8823  {
8824  fclose (backup_volinfo_fp);
8825  }
8826 
8827  if (session != NULL)
8828  {
8829  fileio_abort_restore (thread_p, session);
8830  }
8831 
8832  fileio_page_bitmap_list_destroy (&page_bitmap_list);
8833 
8834  if (lgat_vdes != NULL_VOLDES)
8835  {
8836  fileio_dismount (thread_p, lgat_vdes);
8837  }
8838 
8839  if (!error_expected)
8840  {
8841  logpb_fatal_error (thread_p, false, ARG_FILE_LINE, "logpb_restore");
8842  }
8843 
8844  if (tmp_logfiles_from_backup[0] != '\0')
8845  {
8846  unlink (tmp_logfiles_from_backup);
8847  }
8848 
8849  return error_code;
8850 }
8851 
8852 /*
8853  * logpb_start_where_path - Start where paths for copy/rename volumes
8854  *
8855  * return: NO_ERROR if all OK, ER status otherwise
8856  *
8857  * to_db_fullname(in): Full name of the new database
8858  * toext_path(in): A path if all volumes are placed in one
8859  * place. If NULL is given,
8860  * - If file "fileof_vols_and_wherepaths" is
8861  * given, the path is found in this file.
8862  * - Each volume is copied to same place where
8863  * the volume reside.
8864  * This parameter should be NULL, if the above
8865  * file is given.
8866  * toext_name(in/out): Name to be used for volume extensions when
8867  * individual volume entries are not given in
8868  * file "fileof_vols_and_wherepaths".
8869  * ext_path(in/out): Location for entries
8870  * Set as a side effect to either:
8871  * - toext_path when all vols are placed in
8872  * the same location.
8873  * - alloc_extpath when volumes are copied or
8874  * renamed at the same location as the
8875  * original volumes.
8876  * - NULL when file of "fileof_vols_and_
8877  * wherepaths" is given.
8878  * alloc_extpath(in/out): Set as a side effect to newly malloced area
8879  * when the volumes are copied/renamed in place.
8880  * If an area is allocated, it should be freed
8881  * using free_and_init.
8882  * fileof_vols_and_wherepaths(in): A file is given when the user decides to
8883  * control the copy/rename of the volume by
8884  * individual bases. That is, user decides to
8885  * spread the volumes over several locations and
8886  * or to name the volumes.
8887  * Each volume entry consists of:
8888  * volid from_fullvolname to_fullvolname
8889  * where_paths_fp(in/out): Set as a side effect to file descriptor of
8890  * the given file. The caller must close the
8891  * file, when a pointer is returned.
8892  *
8893  * NOTE: Prepare variables to start finding paths for copying or
8894  * renaming volumes.
8895  */
8896 static int
8897 logpb_start_where_path (const char *to_db_fullname, const char *toext_path, const char **toext_name, char **ext_path,
8898  char **alloc_extpath, const char *fileof_vols_and_wherepaths, FILE ** where_paths_fp)
8899 {
8900  /*
8901  * Get the name of extensions to be used when "fileof_vols_and_wherepaths"
8902  * is not given.
8903  */
8904 
8905  *toext_name = fileio_get_base_file_name (to_db_fullname);
8906  *alloc_extpath = NULL;
8907  *ext_path = NULL;
8908  *where_paths_fp = NULL;
8909 
8910  /*
8911  * Where are the volumes going to be placed ?
8912  * - All or them at same place: toext_path or the same as database
8913  * - The user indicated where to create each individual copy
8914  */
8915 
8916  if (fileof_vols_and_wherepaths != NULL)
8917  {
8918  /*
8919  * The user seems to want to spread the volumes over several locations.
8920  * User must indicate where each individual database volume is going to
8921  * be placed.
8922  */
8923  *where_paths_fp = fopen (fileof_vols_and_wherepaths, "r");
8924  if (*where_paths_fp == NULL)
8925  {
8927  fileof_vols_and_wherepaths);
8928  return ER_LOG_USER_FILE_UNKNOWN;
8929  }
8930  }
8931  /*
8932  * Either all copies are created at the same place, or each individual
8933  * volumes is copied at the original volume location
8934  */
8935  if (toext_path == NULL)
8936  {
8937  /*
8938  * Each volume is copied to the same place where the original volume
8939  * resides
8940  */
8941  *alloc_extpath = (char *) malloc (PATH_MAX);
8942  if (*alloc_extpath == NULL)
8943  {
8944  return ER_FAILED;
8945  }
8946  *ext_path = *alloc_extpath;
8947  }
8948  else
8949  {
8950  /* All the volumes are created in one location */
8951  *ext_path = (char *) toext_path;
8952  }
8953 
8954  return NO_ERROR;
8955 }
8956 
8957 /*
8958  * logpb_next_where_path - Find next path for copy/rename next volume
8959  *
8960  * return: NO_ERROR if all OK, ER status otherwise
8961  *
8962  * to_db_fullname(in): Full name of the new database
8963  * toext_path(in): A path if all volumes are placed in one
8964  * place. If NULL is given,
8965  * - If file "fileof_vols_and_wherepaths" is
8966  * given, the path is found in this file.
8967  * - Each volume is copied to same place where
8968  * the volume reside.
8969  * This parameter should be NULL, if the above
8970  * file is given.
8971  * ext_name(in): Name to be used for volume extensions when
8972  * individual volume entries are not given in
8973  * file "fileof_vols_and_wherepaths".
8974  * ext_path(in): Location for entries
8975  * fileof_vols_and_wherepaths(in): A file is given when the user decides to
8976  * control the copy/rename of the volume by
8977  * individual bases. That is, user decides to
8978  * spread the volumes over several locations and
8979  * or to name the volumes.
8980  * Each volume entry consists of:
8981  * volid from_fullvolname to_fullvolname
8982  * where_paths_fp(in): Pointer to above file if any or NULL
8983  * num_perm_vols(in): Number of permanent volumes in the database.
8984  * volid(in): Next volume that must be processes.
8985  * from_volname(in/out): Current name of volume.
8986  * to_volname(in): New name to be used for the volume.
8987  *
8988  * NOTE: Get the name of next volume to be processed.
8989  */
8990 static int
8991 logpb_next_where_path (const char *to_db_fullname, const char *toext_path, const char *ext_name, char *ext_path,
8992  const char *fileof_vols_and_wherepaths, FILE * where_paths_fp, int num_perm_vols,
8993  VOLID volid, char *from_volname, char *to_volname)
8994 {
8995  const char *current_vlabel;
8996  int from_volid;
8997 #if !defined(WINDOWS)
8998  char link_path[PATH_MAX];
8999  struct stat stat_buf;
9000 #endif
9001  int error_code = NO_ERROR;
9002  char format_string[64];
9003 
9004  current_vlabel = fileio_get_volume_label (volid, PEEK);
9005  sprintf (format_string, "%%d %%%ds %%%ds", PATH_MAX - 1, PATH_MAX - 1);
9006 
9007  /*
9008  * If a file for paths was given, get the name of the "to" volume from it
9009  */
9010  if (where_paths_fp != NULL)
9011  {
9012  if (fscanf (where_paths_fp, format_string, &from_volid, from_volname, to_volname) != 3)
9013  {
9015  fileof_vols_and_wherepaths, num_perm_vols);
9017  }
9018  /*
9019  * Primary volume must be identical to database name
9020  */
9021  if (volid == LOG_DBFIRST_VOLID && strcmp (to_volname, to_db_fullname) != 0)
9022  {
9023 
9024 #if defined(WINDOWS)
9026  fileof_vols_and_wherepaths, volid + 1, from_volid, from_volname, to_volname, (int) volid,
9027  current_vlabel, to_db_fullname);
9028  return ER_ERROR_SEVERITY;
9029 #else /* WINDOWS */
9030  error_code = fileio_symlink (to_volname, to_db_fullname, true);
9031  if (error_code != NO_ERROR)
9032  {
9034  fileof_vols_and_wherepaths, volid + 1, from_volid, from_volname, to_volname, (int) volid,
9035  current_vlabel, to_db_fullname);
9036  return error_code;
9037  }
9038 
9039  strcpy (to_volname, to_db_fullname);
9040 #endif /* WINDOWS */
9041  }
9042  else
9043  {
9044  if (volid != from_volid || util_compare_filepath (current_vlabel, from_volname) != 0)
9045  {
9047  fileof_vols_and_wherepaths, volid + 1, from_volid, from_volname, to_volname, (int) volid,
9048  current_vlabel);
9050  }
9051 
9052 #if !defined(WINDOWS)
9053  if (stat (to_volname, &stat_buf) != -1)
9054  {
9055  if (S_ISCHR (stat_buf.st_mode))
9056  {
9057  fileio_get_directory_path (ext_path, to_db_fullname);
9058  fileio_make_volume_ext_name (link_path, ext_path, ext_name, volid);
9059  error_code = fileio_symlink (to_volname, link_path, true);
9060  if (error_code != NO_ERROR)
9061  {
9062  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_CREATE_LINK, 2, to_volname, link_path);
9063  return error_code;
9064  }
9065 
9066  strcpy (to_volname, link_path);
9067  }
9068  }
9069 #endif /* !WINDOWS */
9070  }
9071  }
9072  else
9073  {
9074  /*
9075  * The decision is done consulting the arguments of the function
9076  */
9077 
9078  /*
9079  * Primary volume must be identical to database name
9080  */
9081  if (volid == LOG_DBFIRST_VOLID)
9082  {
9083  strcpy (to_volname, to_db_fullname);
9084  }
9085  else
9086  {
9087  if (toext_path == NULL)
9088  {
9089  /*
9090  * The volume is copied to the same place where the original volume
9091  * resides
9092  */
9093  if (fileio_get_directory_path (ext_path, current_vlabel) == NULL)
9094  {
9095  ext_path[0] = '\0';
9096  }
9097  }
9098  fileio_make_volume_ext_name (to_volname, ext_path, ext_name, volid);
9099  }
9100  strcpy (from_volname, current_vlabel);
9101  }
9102 
9103  return NO_ERROR;
9104 }
9105 
9106 /*
9107  * logpb_copy_volume - Copy a volume
9108  *
9109  * return: NO_ERROR if all OK, ER status otherwise
9110  *
9111  * from_volid(in): The identifier of the volume to be copied
9112  * to_volname(in): Name of the new volume
9113  * db_creation(in): Creation timestamp for the volume
9114  * to_volchkpt_lsa(in): Checkpoint location to be used in the new volume
9115  *
9116  * NOTE: Copy the volume identified by "from_volid" to "tonew_volname".
9117  */
9118 static int
9119 logpb_copy_volume (THREAD_ENTRY * thread_p, VOLID from_volid, const char *to_volname, INT64 * db_creation,
9120  LOG_LSA * to_volchkpt_lsa)
9121 {
9122  int from_vdes, to_vdes; /* Descriptor for "from" and "to" volumes */
9123  DKNPAGES npages; /* Size of the volume */
9124  int error_code = NO_ERROR;
9125 
9126  /* Find the current pages of the volume and its descriptor */
9127 
9128  npages = xdisk_get_total_numpages (thread_p, from_volid);
9129  from_vdes = fileio_get_volume_descriptor (from_volid);
9130 
9131  /* Flush all dirty pages */
9132  logpb_flush_pages_direct (thread_p);
9133 
9134  error_code = pgbuf_flush_all_unfixed (thread_p, from_volid);
9135  if (error_code != NO_ERROR)
9136  {
9137  return error_code;
9138  }
9139 
9140  if (fileio_synchronize (thread_p, from_vdes, fileio_get_volume_label (from_vdes, PEEK),
9141  FILEIO_SYNC_ALSO_FLUSH_DWB) != from_vdes)
9142  {
9143  return ER_FAILED;
9144  }
9145 
9146  /* Copy the database volume and initialize recovery information on it */
9147 
9148  to_vdes = fileio_copy_volume (thread_p, from_vdes, npages, to_volname, LOG_DBCOPY_VOLID, true);
9149  if (to_vdes == NULL_VOLDES)
9150  {
9151  return ER_FAILED;
9152  }
9153 
9154  /*
9155  * Change the name of the volume, its database creation time and its
9156  * checkpoint lsa
9157  */
9158 
9159  (void) disk_set_creation (thread_p, LOG_DBCOPY_VOLID, to_volname, db_creation, to_volchkpt_lsa, false,
9160  DISK_DONT_FLUSH);
9161 
9162  logpb_flush_pages_direct (thread_p);
9164 
9165  /*
9166  * To set the LSA of temp volume to special temp LSA (-2,-2).
9167  * Especially, in case of copydb.
9168  */
9170 
9171  (void) pgbuf_invalidate_all (thread_p, LOG_DBCOPY_VOLID);
9172  fileio_dismount (thread_p, to_vdes);
9173 
9174  return NO_ERROR;
9175 }
9176 
9177 /*
9178  * logpb_copy_database - Copy a database
9179  *
9180  * return: NO_ERROR if all OK, ER status otherwise
9181  *
9182  * num_perm_vols(in): Number of permanent volume for the database
9183  * to_db_fullname(in): Full name of the new database
9184  * to_logpath(in): Directory where the log volumes reside
9185  * to_prefix_logname(in): Name of the log volumes. It is usually set
9186  * the same as database name. For example, if the value
9187  * is equal to "db", the names of the log volumes created
9188  * are as follow:
9189  * Active_log = db_logactive
9190  * Archive_logs = db_logarchive.0
9191  * db_logarchive.1
9192  * .
9193  * .
9194  * .
9195  * db_logarchive.n
9196  * Log_information = db_loginfo
9197  * Database Backup = db_backup
9198  * toext_path(in): A path is included if all volumes are placed in one
9199  * place/directory. If NULL is given,
9200  * - If file "fileof_vols_and_wherepaths" is given, the
9201  * path is found in this file.
9202  * - Each volume is copied to same place where the volume
9203  * resides.
9204  * NOTE: This parameter should be NULL, if the above file
9205  * is given.
9206  * fileof_vols_and_copypaths(in): A file is given when the user decides to
9207  * control the copy/rename of the volume by
9208  * individual bases. That is, user decides to
9209  * spread the volumes over several locations and
9210  * or to label the volumes with specific names.
9211  * Each volume entry consists of:
9212  * volid from_fullvolname to_fullvolname
9213  *
9214  * NOTE: A new log volume is created for the new database, and each
9215  * data volume of the database is copied to the new database.
9216  * Recovery information from the old database is not included
9217  * onto the copy (i.e., new database). Backups of the old
9218  * are not included either. Thus, a backup of the new database is
9219  * recommended after the copy is done.
9220  *
9221  * NOTE: This function must be run offline. That is, should not be run
9222  * when there are multiusers in the system.
9223  */
9224 int
9225 logpb_copy_database (THREAD_ENTRY * thread_p, VOLID num_perm_vols, const char *to_db_fullname, const char *to_logpath,
9226  const char *to_prefix_logname, const char *toext_path, const char *fileof_vols_and_copypaths)
9227 {
9228  LOG_RECORD_HEADER *eof; /* End of log record */
9229  char from_volname[PATH_MAX]; /* Name of new volume */
9230  FILE *fromfile_paths_fp = NULL; /* Pointer to open file for location of copy files */
9231  int fromfile_volid; /* Volume identifier as an integer */
9232  int to_vdes; /* A volume descriptor */
9233  char to_volname[PATH_MAX]; /* Name of "to" volume */
9234  LOG_PAGE *to_malloc_log_pgptr = NULL; /* Log header page "to" log */
9235  LOG_HEADER *to_hdr; /* Log header for "to" log */
9236  FILE *to_volinfo_fp = NULL; /* Pointer to new volinfo file */
9237  char *alloc_extpath = NULL; /* Copy path for specific volume */
9238  const char *ext_name;
9239  char *ext_path;
9240  VOLID volid;
9241  INT64 db_creation;
9243  bool stop_eof = false;
9244  const char *catmsg;
9245  int error_code;
9246  char format_string[64];
9247  FILEIO_WRITE_MODE write_mode;
9248  char from_mk_path[PATH_MAX] = { 0, };
9249  char to_mk_path[PATH_MAX] = { 0, };
9250 
9251  db_creation = time (NULL);
9252 
9253  /*
9254  * Make sure that the length name of the volumes are OK
9255  */
9256 
9257  error_code = logpb_verify_length (to_db_fullname, to_logpath, to_prefix_logname);
9258  if (error_code != NO_ERROR)
9259  {
9260  /* Names are too long */
9261  return error_code;
9262  }
9263 
9264  /* Do not use DWB at copy DB. In case of crash the data may be recreated from log. */
9265  dwb_destroy (thread_p);
9266 
9267  /*
9268  * Create the DATABASE VOLUME INFORMATION file
9269  */
9270  error_code = logpb_create_volume_info (to_db_fullname);
9271  if (error_code != NO_ERROR)
9272  {
9273  goto error;
9274  }
9275 
9276  /*
9277  * Create and Copy the TDE master key file (_keys)
9278  */
9279  tde_make_keys_file_fullname (from_mk_path, boot_db_full_name (), false);
9280  tde_make_keys_file_fullname (to_mk_path, to_db_fullname, false);
9281  error_code = tde_copy_keys_file (thread_p, to_mk_path, from_mk_path, false, false);
9282  if (error_code != NO_ERROR)
9283  {
9285  /* keep going with out master key file */
9286  }
9287 
9288  /*
9289  * Create a LOG INFORMATION FILE
9290  */
9291 
9292  fileio_make_log_info_name (to_volname, to_logpath, to_prefix_logname);
9293  logpb_create_log_info (to_volname, to_db_fullname);
9294 
9296  if (catmsg == NULL)
9297  {
9298  catmsg = "ACTIVE: %s %d pages\n";
9299  }
9300  error_code = log_dump_log_info (to_volname, false, catmsg, to_volname, log_Gl.hdr.npages + 1);
9301  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
9302  {
9303  goto error;
9304  }
9305 
9306  fileio_make_backup_volume_info_name (to_volname, to_logpath, to_prefix_logname);
9307  if (logpb_add_volume (to_db_fullname, LOG_DBLOG_BKUPINFO_VOLID, to_volname, DISK_UNKNOWN_PURPOSE) !=
9309  {
9310  error_code = ER_FAILED;
9311  goto error;
9312  }
9313 
9314  /*
9315  * FIRST CREATE A NEW LOG FOR THE NEW DATABASE. This log is not a copy of
9316  * of the old log; it is a newly created one.
9317  * Compose the LOG name for the ACTIVE portion of the log.
9318  * Make sure that nobody else is using this database
9319  */
9320 
9321  to_malloc_log_pgptr = (LOG_PAGE *) malloc (LOG_PAGESIZE);
9322  if (to_malloc_log_pgptr == NULL)
9323  {
9324  error_code = ER_FAILED;
9325  goto error;
9326  }
9327 
9328 #if !defined (NDEBUG)
9329  // suppress valgrind complaint.
9330  memset (to_malloc_log_pgptr, LOG_PAGE_INIT_VALUE, LOG_PAGESIZE);
9331 #endif // DEBUG
9332 
9333  fileio_make_log_active_name (to_volname, to_logpath, to_prefix_logname);
9334  if (logpb_add_volume (to_db_fullname, LOG_DBLOG_ACTIVE_VOLID, to_volname, DISK_UNKNOWN_PURPOSE) !=
9336  {
9337  error_code = ER_FAILED;
9338  goto error;
9339  }
9340  to_vdes =
9341  fileio_format (thread_p, to_db_fullname, to_volname, LOG_DBCOPY_VOLID, log_Gl.hdr.npages + 1, false, true, false,
9342  LOG_PAGESIZE, 0, false);
9343  if (to_vdes == NULL_VOLDES)
9344  {
9345  error_code = ER_FAILED;
9346  goto error;
9347  }
9348 
9349  /*
9350  * Write an end of log mark at first append page. This is used to detect the
9351  * end of new log
9352  */
9353 
9354  phy_pageid = LOGPB_PHYSICAL_HEADER_PAGE_ID + 1;
9355  to_malloc_log_pgptr->hdr.logical_pageid = 0;
9356  to_malloc_log_pgptr->hdr.offset = NULL_OFFSET;
9357  to_malloc_log_pgptr->hdr.flags = 0;
9358 
9359  eof = (LOG_RECORD_HEADER *) to_malloc_log_pgptr->area;
9360  eof->trid = LOG_SYSTEM_TRANID + 1;
9361  LSA_SET_NULL (&eof->prev_tranlsa);
9362  LSA_SET_NULL (&eof->back_lsa);
9363  LSA_SET_NULL (&eof->forw_lsa);
9364  eof->type = LOG_END_OF_LOG;
9365 
9366  error_code = logpb_set_page_checksum (thread_p, to_malloc_log_pgptr);
9367  if (error_code != NO_ERROR)
9368  {
9369  fileio_dismount (thread_p, to_vdes);
9370  goto error;
9371  }
9372 
9373  log_Gl.hdr.eof_lsa.pageid = to_malloc_log_pgptr->hdr.logical_pageid;
9374  log_Gl.hdr.eof_lsa.offset = 0;
9375 
9377  if (fileio_write (thread_p, to_vdes, to_malloc_log_pgptr, phy_pageid, LOG_PAGESIZE, write_mode) == NULL)
9378  {
9379  error_code = ER_FAILED;
9380  fileio_dismount (thread_p, to_vdes);
9381  goto error;
9382  }
9383 
9384  /*
9385  * Initialize the active log header from the old log.
9386  */
9387 
9388  /*
9389  * Now, modify the log header. Similar than log_create
9390  */
9391  to_malloc_log_pgptr->hdr.logical_pageid = LOGPB_HEADER_PAGE_ID;
9392  to_malloc_log_pgptr->hdr.offset = NULL_OFFSET;
9393  to_malloc_log_pgptr->hdr.flags = 0;
9394 
9395  to_hdr = (LOG_HEADER *) to_malloc_log_pgptr->area;
9396  error_code = logpb_initialize_header (thread_p, to_hdr, to_prefix_logname, log_Gl.hdr.npages + 1, &db_creation);
9397  if (error_code != NO_ERROR)
9398  {
9399  fileio_dismount (thread_p, to_vdes);
9400  goto error;
9401  }
9402 
9403  if (logpb_copy_log_header (thread_p, to_hdr, &log_Gl.hdr) != NO_ERROR)
9404  {
9405  fileio_dismount (thread_p, to_vdes);
9406  goto error;
9407  }
9408 
9409  error_code = logpb_set_page_checksum (thread_p, to_malloc_log_pgptr);
9410  if (error_code != NO_ERROR)
9411  {
9412  fileio_dismount (thread_p, to_vdes);
9413  goto error;
9414  }
9415 
9416  /* Now write the log header */
9417  phy_pageid = logpb_to_physical_pageid (to_malloc_log_pgptr->hdr.logical_pageid);
9418  if (fileio_write (thread_p, to_vdes, to_malloc_log_pgptr, phy_pageid, LOG_PAGESIZE, write_mode) == NULL)
9419  {
9420  error_code = ER_FAILED;
9421  fileio_dismount (thread_p, to_vdes);
9422  goto error;
9423  }
9424 
9425  /* Dismount the copy of the log */
9426  fileio_dismount (thread_p, to_vdes);
9427 
9428  /*
9429  * Start the COPYING all INFORMATION VOLUMES
9430  */
9431 
9432  /*
9433  * Prepare the where path for the volumes according to the input
9434  */
9435 
9436  error_code =
9437  logpb_start_where_path (to_db_fullname, toext_path, &ext_name, &ext_path, &alloc_extpath, fileof_vols_and_copypaths,
9438  &fromfile_paths_fp);
9439  if (error_code != NO_ERROR)
9440  {
9441  goto error;
9442  }
9443 
9444  for (volid = LOG_DBFIRST_VOLID; volid != NULL_VOLID; volid = fileio_find_next_perm_volume (thread_p, volid))
9445  {
9446  error_code =
9447  logpb_next_where_path (to_db_fullname, toext_path, ext_name, ext_path, fileof_vols_and_copypaths,
9448  fromfile_paths_fp, num_perm_vols, volid, from_volname, to_volname);
9449  if (error_code != NO_ERROR)
9450  {
9451  goto error;
9452  }
9453  error_code = logpb_copy_volume (thread_p, volid, to_volname, &to_hdr->db_creation, &to_hdr->chkpt_lsa);
9454  if (error_code != NO_ERROR)
9455  {
9456  goto error;
9457  }
9458 
9459  /* Write information about this volume in the volume information file */
9460  if (logpb_add_volume (to_db_fullname, volid, to_volname, DB_PERMANENT_DATA_PURPOSE) != volid)
9461  {
9462  error_code = ER_FAILED;
9463  goto error;
9464  }
9465  }
9466 
9467  /*
9468  * We need to change the name of the volumes in our internal tables.
9469  * That is, first volume points to second volume
9470  * second volume points to third volume
9471  * and so on..
9472  * last volume points to nobody
9473  */
9474 
9475  fileio_make_volume_info_name (to_volname, to_db_fullname);
9476  sprintf (format_string, "%%d %%%ds", PATH_MAX - 1);
9477 
9478  to_volinfo_fp = fopen (to_volname, "r");
9479  if (to_volinfo_fp != NULL)
9480  {
9481  volid = NULL_VOLID;
9482  while (true)
9483  {
9484  if (fscanf (to_volinfo_fp, format_string, &fromfile_volid, to_volname) != 2)
9485  {
9486  stop_eof = true;
9487  fromfile_volid = NULL_VOLID;
9488  to_volname[0] = '\0';
9489  }
9490  else
9491  {
9492  if ((VOLID) fromfile_volid < LOG_DBFIRST_VOLID)
9493  {
9494  continue;
9495  }
9496  }
9497 
9498  /*
9499  * The previous volume must point to new volume
9500  */
9501 
9502  if (volid != NULL_VOLID)
9503  {
9504  error_code = disk_set_link (thread_p, LOG_DBCOPY_VOLID, fromfile_volid, to_volname, false, DISK_FLUSH);
9505  if (error_code != NO_ERROR)
9506  {
9507  fileio_dismount (thread_p, to_vdes);
9508  goto error;
9509  }
9510  logpb_flush_pages_direct (thread_p);
9512  if (error_code != NO_ERROR)
9513  {
9514  fileio_dismount (thread_p, to_vdes);
9515  goto error;
9516  }
9517  if (fileio_synchronize (thread_p, to_vdes, to_volname, FILEIO_SYNC_ALSO_FLUSH_DWB) != to_vdes)
9518  {
9519  fileio_dismount (thread_p, to_vdes);
9520  error_code = ER_FAILED;
9521  goto error;
9522  }
9523  (void) pgbuf_invalidate_all (thread_p, LOG_DBCOPY_VOLID);
9524  fileio_dismount (thread_p, to_vdes);
9525  }
9526 
9527  if (stop_eof == true)
9528  {
9529  break;
9530  }
9531 
9532  /*
9533  * Now, mount the current volume
9534  */
9535  volid = (VOLID) fromfile_volid;
9536 
9537  to_vdes = fileio_mount (thread_p, log_Db_fullname, to_volname, LOG_DBCOPY_VOLID, false, false);
9538  if (to_vdes == NULL_VOLDES)
9539  {
9540  error_code = ER_FAILED;
9541  goto error;
9542  }
9543  }
9544  fclose (to_volinfo_fp);
9545  }
9546 
9547  if (fromfile_paths_fp != NULL)
9548  {
9549  fclose (fromfile_paths_fp);
9550  }
9551 
9552  if (alloc_extpath != NULL)
9553  {
9554  free_and_init (alloc_extpath);
9555  }
9556 
9557  free_and_init (to_malloc_log_pgptr);
9558 
9559  return NO_ERROR;
9560 
9561  /* ******** */
9562 error:
9563 
9564  if (to_malloc_log_pgptr)
9565  {
9566  free_and_init (to_malloc_log_pgptr);
9567  }
9568 
9569  if (fromfile_paths_fp != NULL)
9570  {
9571  fclose (fromfile_paths_fp);
9572  }
9573 
9574  if (alloc_extpath != NULL)
9575  {
9576  free_and_init (alloc_extpath);
9577  }
9578 
9579  /* Destroy the log */
9580 
9581  fileio_make_log_active_name (to_volname, to_logpath, to_prefix_logname);
9582  fileio_unformat (thread_p, to_volname);
9583  fileio_make_log_info_name (to_volname, to_logpath, to_prefix_logname);
9584  fileio_unformat (thread_p, to_volname);
9585 
9586  /*
9587  * Rewind the volume information to destroy any created volumes if any
9588  */
9589 
9590  sprintf (format_string, "%%*d %%%ds", PATH_MAX - 1);
9591  if (to_volinfo_fp != NULL)
9592  {
9593  fclose (to_volinfo_fp);
9594  fileio_make_volume_info_name (to_volname, to_db_fullname);
9595  if ((to_volinfo_fp = fopen (to_volname, "r")) != NULL)
9596  {
9597  while (true)
9598  {
9599  if (fscanf (to_volinfo_fp, format_string, to_volname) != 1)
9600  {
9601  break;
9602  }
9603  fileio_unformat (thread_p, to_volname);
9604  }
9605  fclose (to_volinfo_fp);
9606  /* Destroy the volinfo file */
9607  fileio_make_volume_info_name (to_volname, to_db_fullname);
9608  fileio_unformat (thread_p, to_volname);
9609  }
9610  }
9611 
9612  return error_code;
9613 }
9614 
9615 /*
9616  * logpb_rename_all_volumes_files - Rename all volumes/files of the database
9617  *
9618  * return: NO_ERROR if all OK, ER status otherwise
9619  *
9620  * num_perm_vols(in):
9621  * to_db_fullname(in): New full name of the database
9622  * to_logpath(in): Directory where the log volumes reside
9623  * to_prefix_logname(in): New prefix name for log volumes. It is usually set
9624  * as database name. For example, if the value is equal to
9625  * "db", the names of the log volumes created are as
9626  * follow:
9627  * Active_log = db_logactive
9628  * Archive_logs = db_logarchive.0
9629  * db_logarchive.1
9630  * .
9631  * .
9632  * .
9633  * db_logarchive.n
9634  * Log_information = db_loginfo
9635  * Database Backup = db_backup
9636  * toext_path(in):
9637  * fileof_vols_and_renamepaths(in):
9638  * extern_rename(in): Rename the volumes/files at OS too.
9639  * force_delete(in): Force delete backup volumes and information file
9640  *
9641  * NOTE:All volumes/files of the database are renamed according to the
9642  * new specifications. This function performs a soft rename, it
9643  * will no copy files.
9644  *
9645  * This function must be run offline. That is, it should not be
9646  * run when there are multiusers in the system.
9647  */
9648 int
9649 logpb_rename_all_volumes_files (THREAD_ENTRY * thread_p, VOLID num_perm_vols, const char *to_db_fullname,
9650  const char *to_logpath, const char *to_prefix_logname, const char *toext_path,
9651  const char *fileof_vols_and_renamepaths, bool extern_rename, bool force_delete)
9652 {
9653  char from_volname[PATH_MAX]; /* Name of new volume */
9654  char to_volname[PATH_MAX]; /* Name of "to" volume */
9655  char from_mk_path[PATH_MAX];
9656  char to_mk_path[PATH_MAX];
9657  char *alloc_extpath = NULL; /* Copy path for specific volume */
9658  FILE *to_volinfo_fp = NULL; /* Pointer to new volinfo file */
9659  const char *ext_name;
9660  char *ext_path;
9661  VOLID volid, prev_volid;
9662  FILE *fromfile_paths_fp = NULL; /* Pointer to open file for location of rename files */
9663  int i;
9664  const char *catmsg;
9665 
9666  struct stat ext_path_stat;
9667  struct stat vol_stat;
9668  char real_pathbuf[PATH_MAX];
9669  int error_code = NO_ERROR;
9670 
9671  if (toext_path != NULL && realpath ((char *) toext_path, real_pathbuf) != NULL)
9672  {
9673  toext_path = real_pathbuf;
9674  }
9675 
9676  /*
9677  * Make sure that the length name of the volumes are OK
9678  */
9679 
9680  error_code = logpb_verify_length (to_db_fullname, to_logpath, to_prefix_logname);
9681  if (error_code != NO_ERROR)
9682  {
9683  /* Names are too long */
9684  return error_code;
9685  }
9686 
9687  /* toext_path validation check. */
9688  if (toext_path != NULL)
9689  {
9690  if (stat (toext_path, &ext_path_stat))
9691  {
9693  error_code = ER_TM_GET_STAT_FAIL;
9694  goto error;
9695  }
9696  if ((access (toext_path, W_OK) < 0) || !(S_ISDIR (ext_path_stat.st_mode)))
9697  {
9699  error_code = ER_TM_IS_NOT_WRITEABLE;
9700  goto error;
9701  }
9702 
9703  error_code =
9704  logpb_start_where_path (to_db_fullname, toext_path, &ext_name, &ext_path, &alloc_extpath,
9705  fileof_vols_and_renamepaths, &fromfile_paths_fp);
9706  if (error_code != NO_ERROR)
9707  {
9708  goto error;
9709  }
9710 
9711  for (volid = LOG_DBFIRST_VOLID; volid != NULL_VOLID; volid = fileio_find_next_perm_volume (thread_p, volid))
9712  {
9713  error_code =
9714  logpb_next_where_path (to_db_fullname, toext_path, ext_name, ext_path, fileof_vols_and_renamepaths,
9715  fromfile_paths_fp, num_perm_vols, volid, from_volname, to_volname);
9716  if (error_code != NO_ERROR)
9717  {
9718  goto error;
9719  }
9720  if (stat (from_volname, &vol_stat))
9721  {
9723  error_code = ER_TM_GET_STAT_FAIL;
9724  goto error;
9725  }
9726  if ((volid > 0) && (ext_path_stat.st_dev != vol_stat.st_dev))
9727  {
9728  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TM_CROSS_DEVICE_LINK, 2, from_volname, toext_path);
9729  error_code = ER_TM_CROSS_DEVICE_LINK;
9730  goto error;
9731  }
9732  }
9733  }
9734 
9735  if (log_Gl.archive.vdes != NULL_VOLDES)
9736  {
9737  logpb_dismount_log_archive (thread_p);
9738  }
9739 
9741  {
9742  /* Destroy temporary log archive */
9745  /* Destroy temporary removed log archived */
9747  }
9748 
9749  if (force_delete)
9750  {
9751  /*
9752  * REMOVE ONLINE BACKUPS OF PRESENT DATABASE
9753  * Obtain the name of the backups from the backup volume information file.
9754  */
9755 
9756  to_volinfo_fp = fopen (log_Name_bkupinfo, "r");
9757  if (to_volinfo_fp != NULL)
9758  {
9759 
9761  {
9762  /* Remove any backups that have been created up to now */
9763  fileio_remove_all_backup (thread_p, -1);
9765  }
9766 
9767  fclose (to_volinfo_fp);
9768 
9769  /* Destroy the backup volume information */
9770  fileio_unformat (thread_p, log_Name_bkupinfo);
9771  }
9772  }
9773 
9774  /*
9775  * REMOVE ANY LOG ARCHIVES from present database
9776  */
9777 
9778  for (i = log_Gl.hdr.last_deleted_arv_num + 1; i < log_Gl.hdr.nxarv_num; i++)
9779  {
9781  /*
9782  * Just to avoid the warning, the volume is check first
9783  */
9784  if (fileio_is_volume_exist (from_volname) == true)
9785  {
9786  fileio_unformat (thread_p, from_volname);
9787  }
9788  }
9789 
9790  /*
9791  * RENAME LOG ACTIVE
9792  */
9793 
9794  /*
9795  * Modify the name in the log header. Similar from log_create
9796  */
9797 
9798  log_Gl.hdr.nxarv_num = 0;
9804  strcpy (log_Gl.hdr.prefix_name, to_prefix_logname);
9805 
9806  logpb_flush_pages_direct (thread_p);
9807  logpb_flush_header (thread_p);
9808 
9809  if (extern_rename == true)
9810  {
9811  logpb_finalize_pool (thread_p);
9812  fileio_dismount (thread_p, log_Gl.append.vdes);
9813 
9814  fileio_make_log_active_name (to_volname, to_logpath, to_prefix_logname);
9816  {
9817  log_Gl.append.vdes = fileio_mount (thread_p, to_db_fullname, to_volname, LOG_DBLOG_ACTIVE_VOLID, true, false);
9818  }
9819  else
9820  {
9821  log_Gl.append.vdes =
9823  error_code = ER_FAILED;
9824  goto error;
9825  }
9826 
9827  /* Get the append page */
9828  error_code = logpb_initialize_pool (thread_p);
9829  if (error_code != NO_ERROR)
9830  {
9831  goto error;
9832  }
9833  if (logpb_fetch_start_append_page (thread_p) != NO_ERROR)
9834  {
9835  error_code = ER_FAILED;
9836  goto error;
9837  }
9838  }
9839 
9840  /*
9841  * Create the DATABASE VOLUME INFORMATION file
9842  */
9843 
9844  /*
9845  * Destroy the old VOLUME INFORMATION AND LOG INFORMATION. Then, create
9846  * them back.
9847  */
9848  fileio_unformat (thread_p, log_Name_volinfo);
9849  fileio_unformat (thread_p, log_Name_info);
9850 
9851  error_code = logpb_create_volume_info (to_db_fullname);
9852  if (error_code != NO_ERROR)
9853  {
9854  goto error;
9855  }
9856 
9857  tde_make_keys_file_fullname (from_mk_path, boot_db_full_name (), false);
9858  tde_make_keys_file_fullname (to_mk_path, to_db_fullname, false);
9859 
9860  if (fileio_rename (LOG_DBTDE_KEYS_VOLID, from_mk_path, to_mk_path) != NULL)
9861  {
9862  /* Nothing, tde keys file can be unavailable */
9863  }
9864 
9865 
9866  fileio_make_log_info_name (to_volname, to_logpath, to_prefix_logname);
9867  logpb_create_log_info (to_volname, to_db_fullname);
9868 
9870  if (catmsg == NULL)
9871  {
9872  catmsg = "COMMENT: from renamed database = %s\n";
9873  }
9874  error_code = log_dump_log_info (to_volname, false, catmsg, log_Db_fullname);
9875  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
9876  {
9877  goto error;
9878  }
9879 
9881  if (catmsg == NULL)
9882  {
9883  catmsg = "ACTIVE: %s %d pages\n";
9884  }
9885  error_code = log_dump_log_info (to_volname, false, catmsg, to_volname, log_Gl.hdr.npages + 1);
9886  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
9887  {
9888  goto error;
9889  }
9890 
9891  /*
9892  * Add the backup information and the log active to the volume
9893  * information
9894  */
9895  fileio_make_backup_volume_info_name (to_volname, to_logpath, to_prefix_logname);
9896  if (logpb_add_volume (to_db_fullname, LOG_DBLOG_BKUPINFO_VOLID, to_volname, DISK_UNKNOWN_PURPOSE) !=
9898  {
9899  error_code = ER_FAILED;
9900  goto error;
9901  }
9902 
9903  fileio_make_log_active_name (to_volname, to_logpath, to_prefix_logname);
9904  if (logpb_add_volume (to_db_fullname, LOG_DBLOG_ACTIVE_VOLID, to_volname, DISK_UNKNOWN_PURPOSE) !=
9906  {
9907  error_code = ER_FAILED;
9908  goto error;
9909  }
9910 
9911  /*
9912  * Start the RENAMING all DATA VOLUMES
9913  */
9914 
9915  /*
9916  * Prepare the where path for the volumes according to the input
9917  */
9918 
9919  error_code =
9920  logpb_start_where_path (to_db_fullname, toext_path, &ext_name, &ext_path, &alloc_extpath,
9921  fileof_vols_and_renamepaths, &fromfile_paths_fp);
9922  if (error_code != NO_ERROR)
9923  {
9924  goto error;
9925  }
9926 
9927  for (volid = LOG_DBFIRST_VOLID; volid != NULL_VOLID; volid = fileio_find_next_perm_volume (thread_p, volid))
9928  {
9929  /* Change the name of the volume */
9930  error_code =
9931  logpb_next_where_path (to_db_fullname, toext_path, ext_name, ext_path, fileof_vols_and_renamepaths,
9932  fromfile_paths_fp, num_perm_vols, volid, from_volname, to_volname);
9933  if (error_code != NO_ERROR)
9934  {
9935  goto error;
9936  }
9937 
9938  error_code =
9939  disk_set_creation (thread_p, volid, to_volname, &log_Gl.hdr.db_creation, &log_Gl.hdr.chkpt_lsa, true,
9940  DISK_DONT_FLUSH);
9941  if (error_code != NO_ERROR)
9942  {
9943  goto error;
9944  }
9945 
9946  /*
9947  * We need to change the name of the volumes in our internal tables.
9948  * That is, first volume points to second volume
9949  * second volume points to third volume
9950  * and so on..
9951  * last volume points to nobody
9952  */
9953 
9954  if (volid != LOG_DBFIRST_VOLID)
9955  {
9956  prev_volid = fileio_find_previous_perm_volume (thread_p, volid);
9957  error_code = disk_set_link (thread_p, prev_volid, volid, to_volname, false, DISK_FLUSH);
9958  if (error_code != NO_ERROR)
9959  {
9960  goto error;
9961  }
9962  }
9963 
9964  /*
9965  * Now flush every single page of this volume, dismount the volume, rename
9966  * the volume, and mount the volume
9967  */
9968  logpb_flush_pages_direct (thread_p);
9969  error_code = pgbuf_flush_all (thread_p, volid);
9970  if (error_code != NO_ERROR)
9971  {
9972  goto error;
9973  }
9976  {
9977  error_code = ER_FAILED;
9978  goto error;
9979  }
9980 
9981  (void) pgbuf_invalidate_all (thread_p, volid);
9982 
9983  if (extern_rename == true)
9984  {
9985  fileio_dismount (thread_p, fileio_get_volume_descriptor (volid));
9986  if (fileio_rename (volid, from_volname, to_volname) != NULL)
9987  {
9988  (void) fileio_mount (thread_p, to_db_fullname, to_volname, volid, false, false);
9989  }
9990  else
9991  {
9992  (void) fileio_mount (thread_p, log_Db_fullname, from_volname, volid, false, false);
9993  error_code = ER_FAILED;
9994  goto error;
9995  }
9996  }
9997 
9998  /* Write information about this volume in the volume information file */
9999  if (logpb_add_volume (to_db_fullname, volid, to_volname, DB_PERMANENT_DATA_PURPOSE) != volid)
10000  {
10001  error_code = ER_FAILED;
10002  goto error;
10003  }
10004  }
10005 
10006  if (fromfile_paths_fp != NULL)
10007  {
10008  fclose (fromfile_paths_fp);
10009  }
10010 
10011  if (alloc_extpath != NULL)
10012  {
10013  free_and_init (alloc_extpath);
10014  }
10015 
10016  /* Indicate the new names */
10017  error_code = logpb_initialize_log_names (thread_p, to_db_fullname, to_logpath, to_prefix_logname);
10018  return error_code;
10019 
10020  /* ******* */
10021 error:
10022  /* May need to rename some volumes back */
10023 
10024  if (to_volinfo_fp != NULL)
10025  {
10026  fclose (to_volinfo_fp);
10027  }
10028 
10029  if (fromfile_paths_fp != NULL)
10030  {
10031  fclose (fromfile_paths_fp);
10032  }
10033 
10034  if (alloc_extpath != NULL)
10035  {
10036  free_and_init (alloc_extpath);
10037  }
10038 
10039  /* May need to rename back whatever was renamed */
10040 
10041  return error_code;
10042 }
10043 
10044 /*
10045  * logpb_delete - Delete all log files and database backups
10046  *
10047  * return: NO_ERROR if all OK, ER status otherwise
10048  *
10049  * num_perm_vols(in):
10050  * db_fullname(in): Full name of the database
10051  * logpath(in): Directory where the log volumes reside
10052  * prefix_logname(in): Name of the log volumes. It is usually set as database
10053  * name. For example, if the value is equal to "db", the
10054  * names of the log volumes created are as follow:
10055  * Active_log = db_logactive
10056  * Archive_logs = db_logarchive.0
10057  * db_logarchive.1
10058  * .
10059  * .
10060  * .
10061  * db_logarchive.n
10062  * Log_information = db_loginfo
10063  * Database Backup = db_backup
10064  * force_delete(in):
10065  *
10066  * NOTE:All log volumes (active, archives) and database backups that
10067  * are accessible (i.e., located on disk) are removed from the
10068  * system. This is a very dangerous operation since the database
10069  * cannot be recovered after this operation is done. It is
10070  * recommended to backup the database and put the backup on tape
10071  * or outside the log and backup directories before this
10072  * operation is done.
10073  *
10074  * This function must be run offline. That is, it should not be
10075  * run when there are multiusers in the system.
10076  */
10077 int
10078 logpb_delete (THREAD_ENTRY * thread_p, VOLID num_perm_vols, const char *db_fullname, const char *logpath,
10079  const char *prefix_logname, bool force_delete)
10080 {
10081  char *vlabel; /* Name of volume */
10082  char vol_fullname[PATH_MAX]; /* Name of volume */
10083  LOG_HEADER disk_hdr; /* Log header area */
10084  LOG_HEADER *loghdr; /* Log header pointer */
10085  VOLID volid;
10086  FILE *db_volinfo_fp = NULL;
10087  int read_int_volid;
10088  int i;
10089  int error_code = NO_ERROR;
10090  char format_string[64];
10091 
10092  /*
10093  * FIRST: Destroy data volumes of the database.
10094  * That is, the log, and information files are not removed at this point.
10095  */
10096 
10097  /* If the system is not restarted, read the header directly from disk */
10098  if (num_perm_vols < 0 || log_Gl.trantable.area == NULL || log_Pb.buffers == NULL)
10099  {
10100  /*
10101  * The system is not restarted. Read the log header from disk and remove
10102  * the data volumes by reading the database volume information
10103  */
10104 
10105  er_clear ();
10106  error_code = logpb_initialize_log_names (thread_p, db_fullname, logpath, prefix_logname);
10107  if (error_code != NO_ERROR)
10108  {
10109  return error_code;
10110  }
10111 
10113  || (log_Gl.append.vdes =
10114  fileio_mount (thread_p, db_fullname, log_Name_active, LOG_DBLOG_ACTIVE_VOLID, true,
10115  false)) == NULL_VOLDES)
10116  {
10117  /* Unable to mount the active log */
10118  if (er_errid () == ER_IO_MOUNT_LOCKED)
10119  {
10120  return ER_IO_MOUNT_LOCKED;
10121  }
10122  else
10123  {
10124  loghdr = NULL;
10125  }
10126  }
10127  else
10128  {
10129  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
10130  LOG_PAGE *log_pgptr;
10131 
10132  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
10133  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
10134 
10135  /* Initialize the buffer pool, so we can read the header */
10136  if (logpb_Initialized == false)
10137  {
10138  error_code = logpb_initialize_pool (thread_p);
10139  if (error_code != NO_ERROR)
10140  {
10141  return error_code;
10142  }
10143  }
10144  logpb_fetch_header_with_buffer (thread_p, &disk_hdr, log_pgptr);
10145  logpb_finalize_pool (thread_p);
10146  fileio_dismount (thread_p, log_Gl.append.vdes);
10148  loghdr = &disk_hdr;
10149  /*
10150  * Make sure that the log is a log file and that it is compatible
10151  * with the running database and system
10152  */
10153  if (loghdr->db_compatibility != rel_disk_compatible ())
10154  {
10155  loghdr = NULL;
10156  }
10157  else if (loghdr->db_iopagesize != IO_PAGESIZE || loghdr->db_logpagesize != LOG_PAGESIZE)
10158  {
10159  /* Pagesize is incorrect,...reset it and call again... */
10160  if (db_set_page_size (loghdr->db_iopagesize, loghdr->db_logpagesize) != NO_ERROR)
10161  {
10162  loghdr = NULL;
10163  }
10164  else
10165  {
10166  error_code = logtb_define_trantable_log_latch (thread_p, -1);
10167  if (error_code != NO_ERROR)
10168  {
10169  return error_code;
10170  }
10171  error_code =
10172  logpb_delete (thread_p, num_perm_vols, db_fullname, logpath, prefix_logname, force_delete);
10173  return error_code;
10174  }
10175  }
10176  }
10177 
10178  /*
10179  * DESTROY DATA VOLUMES using the database volume information since
10180  * the database system is not restarted.
10181  *
10182  * NOTE: only data volumes are removed, logs, and information files
10183  * are not removed at this point.
10184  */
10185 
10186  fileio_make_volume_info_name (vol_fullname, db_fullname);
10187  sprintf (format_string, "%%d %%%ds", PATH_MAX - 1);
10188 
10189  db_volinfo_fp = fopen (vol_fullname, "r");
10190  if (db_volinfo_fp != NULL)
10191  {
10192  while (true)
10193  {
10194  if (fscanf (db_volinfo_fp, format_string, &read_int_volid, vol_fullname) != 2)
10195  {
10196  break;
10197  }
10198 
10199  volid = (VOLID) read_int_volid;
10200  /*
10201  * Remove data volumes at this point
10202  */
10203  switch (volid)
10204  {
10205  case LOG_DBVOLINFO_VOLID:
10206  case LOG_DBLOG_INFO_VOLID:
10209  case LOG_DBTDE_KEYS_VOLID:
10210  continue;
10211  default:
10212  fileio_unformat (thread_p, vol_fullname);
10213  }
10214  }
10215 
10216  fclose (db_volinfo_fp);
10217  }
10218  else
10219  {
10220  /* Destory at least the database main volume */
10221  fileio_unformat (thread_p, db_fullname);
10222  }
10223  }
10224  else
10225  {
10226  loghdr = &log_Gl.hdr;
10227  /*
10228  * DESTROY DATA VOLUMES
10229  */
10230  for (volid = LOG_DBFIRST_VOLID; volid != NULL_VOLID; volid = fileio_find_next_perm_volume (thread_p, volid))
10231  {
10232  vlabel = fileio_get_volume_label (volid, ALLOC_COPY);
10233  if (vlabel != NULL)
10234  {
10235  (void) pgbuf_invalidate_all (thread_p, volid);
10236  fileio_dismount (thread_p, fileio_get_volume_descriptor (volid));
10237  fileio_unformat (thread_p, vlabel);
10238  free (vlabel);
10239  }
10240  }
10241  }
10242 
10243  /* destroy the database volume information */
10244  fileio_make_volume_info_name (vol_fullname, db_fullname);
10245  fileio_unformat (thread_p, vol_fullname);
10246 
10247  /* destroy the TDE keys volume information */
10248  tde_make_keys_file_fullname (vol_fullname, db_fullname, true);
10249  fileio_unformat (thread_p, vol_fullname);
10250 
10251  /* Destroy DWB, if still exists. */
10252  fileio_make_dwb_name (vol_fullname, log_Path, log_Prefix);
10253  if (fileio_is_volume_exist (vol_fullname))
10254  {
10255  fileio_unformat (thread_p, vol_fullname);
10256  }
10257 
10258  if (force_delete)
10259  {
10260  /*
10261  * SECOND: Destroy backups of data volumes, and the backup log information
10262  * The backups are located by reading the backup info log.
10263  */
10264 
10265  db_volinfo_fp = fopen (log_Name_bkupinfo, "r");
10266  if (db_volinfo_fp != NULL)
10267  {
10268 
10270  {
10271  /* Remove any backups that have been created up to now */
10272  fileio_remove_all_backup (thread_p, -1);
10274  }
10275 
10276  fclose (db_volinfo_fp);
10277 
10278  /* Now, destroy the backup volume information */
10279  fileio_unformat (thread_p, log_Name_bkupinfo);
10280  }
10281  }
10282 
10283  /*
10284  * THIRD: Destroy log active, online log archives, and log information
10285  */
10286 
10287  /* If there is any archive current mounted, dismount the archive */
10289  {
10290  logpb_dismount_log_archive (thread_p);
10291  }
10292 
10293  /* Destroy online log archives */
10294  if (loghdr != NULL)
10295  {
10296  for (i = loghdr->last_deleted_arv_num + 1; i < loghdr->nxarv_num; i++)
10297  {
10299  fileio_unformat (thread_p, vol_fullname);
10300  }
10301  }
10302 
10304  {
10305  /* Destroy temporary log archive */
10308  /* Destroy temporary removed log archived */
10310  }
10311 
10312  /* Now undefine all pages */
10314  {
10315  logpb_finalize_pool (thread_p);
10316  (void) pgbuf_invalidate_all (thread_p, NULL_VOLID);
10317  logtb_undefine_trantable (thread_p);
10318  if (log_Gl.append.vdes != NULL_VOLDES)
10319  {
10320  fileio_dismount (thread_p, log_Gl.append.vdes);
10322  }
10324  }
10325 
10326  fileio_unformat (thread_p, log_Name_active);
10327  fileio_unformat (thread_p, log_Name_info);
10328 
10329  return NO_ERROR;
10330 }
10331 
10332 /*
10333  * logpb_check_if_exists -
10334  *
10335  * return:
10336  *
10337  * fname(in):
10338  * first_vol(in):
10339  *
10340  * NOTE:
10341  */
10342 static bool
10343 logpb_check_if_exists (const char *fname, char *first_vol)
10344 {
10345  struct stat stat_buf;
10346 
10347  if (stat (fname, &stat_buf) != 0)
10348  {
10349  return false; /* not exist */
10350  }
10352  if (first_vol[0] == 0)
10353  {
10354  strcpy (first_vol, fname);
10355  }
10356  return true;
10357 }
10358 
10359 /*
10360  * logpb_check_exist_any_volumes - check existence of DB files
10361  *
10362  * return: NO_ERROR or error code
10363  *
10364  * db_fullname(in): Full name of the database
10365  * logpath(in): Directory where the log volumes reside
10366  * prefix_logname(in): Name of the log volumes.
10367  * first_vol(in):
10368  *
10369  * NOTE: All log volumes (active, archives) and database backups that
10370  * are accessible (i.e., located on disk) are checked
10371  */
10372 int
10373 logpb_check_exist_any_volumes (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
10374  const char *prefix_logname, char *first_vol, bool * is_exist)
10375 {
10376  int exist_cnt;
10377  int error_code = NO_ERROR;
10378 
10379  exist_cnt = 0;
10380  first_vol[0] = 0;
10381 
10382  *is_exist = false;
10383 
10384  error_code = logpb_initialize_log_names (thread_p, db_fullname, logpath, prefix_logname);
10385  if (error_code != NO_ERROR)
10386  {
10387  return error_code;
10388  }
10389  exist_cnt += logpb_check_if_exists (db_fullname, first_vol) ? 1 : 0;
10390  exist_cnt += logpb_check_if_exists (log_Name_active, first_vol) ? 1 : 0;
10391  exist_cnt += logpb_check_if_exists (log_Name_info, first_vol) ? 1 : 0;
10392  exist_cnt += logpb_check_if_exists (log_Name_volinfo, first_vol) ? 1 : 0;
10393 
10394  if (exist_cnt > 0)
10395  {
10396  *is_exist = true;
10397  }
10398  else
10399  {
10400  *is_exist = false;
10401  }
10402 
10403  return error_code;
10404 }
10405 
10406 /*
10407  *
10408  * LOG FATAL ERRORS
10409  *
10410  */
10411 
10412 /*
10413  * logpb_fatal_error - Log error
10414  *
10415  * return: nothing
10416  *
10417  * log_exit(in):
10418  * file_name(in):
10419  * lineno(in):
10420  * fmt(in):
10421  * va_alist(in): Variable number of arguments (just like fprintf)
10422  *
10423  * NOTE: An error was found during logging. A short error message is
10424  * produced on the stderr describing the error. Currently, the
10425  * database is exited.
10426  */
10427 void
10428 logpb_fatal_error (THREAD_ENTRY * thread_p, bool log_exit, const char *file_name, const int lineno, const char *fmt,
10429  ...)
10430 {
10431  va_list ap;
10432 
10433  va_start (ap, fmt);
10434  logpb_fatal_error_internal (thread_p, log_exit, true, file_name, lineno, fmt, ap);
10435  va_end (ap);
10436 }
10437 
10438 void
10439 logpb_fatal_error_exit_immediately_wo_flush (THREAD_ENTRY * thread_p, const char *file_name, const int lineno,
10440  const char *fmt, ...)
10441 {
10442  va_list ap;
10443 
10444  va_start (ap, fmt);
10445  logpb_fatal_error_internal (thread_p, true, false, file_name, lineno, fmt, ap);
10446  va_end (ap);
10447 }
10448 
10449 static void
10450 logpb_fatal_error_internal (THREAD_ENTRY * thread_p, bool log_exit, bool need_flush, const char *file_name,
10451  const int lineno, const char *fmt, va_list ap)
10452 {
10453  const char *msglog;
10454  char msg[LINE_MAX];
10455 
10456  /* call er_set() to print call stack to the log */
10457  vsnprintf (msg, LINE_MAX, fmt, ap);
10458  er_set (ER_FATAL_ERROR_SEVERITY, file_name, lineno, ER_LOG_FATAL_ERROR, 1, msg);
10459 
10460  /*
10461  * Flush any unfixed, dirty pages before the system exits. This is done
10462  * to make sure that all committed actions are reflected on disk.
10463  * Unfortunately, we may be placing some uncommitted action od disk. This
10464  * will be fixed by our recovery process. Note if the user runs the pathdb,
10465  * utility after this, the uncommitted actions will be considered as
10466  * committed.
10467  */
10468 
10469  if (log_exit == true && need_flush == true && log_Gl.append.log_pgptr != NULL)
10470  {
10471  /* Flush up to the smaller of the previous LSA record or the previous flushed append page. */
10472  LOG_LSA tmp_lsa1, tmp_lsa2;
10473  static int in_fatal = false;
10474 
10475  if (in_fatal == false)
10476  {
10477  in_fatal = true;
10478 
10480  {
10481  LSA_COPY (&tmp_lsa1, &log_Gl.append.prev_lsa);
10482  }
10483  else
10484  {
10485  /* TODO : valid code ?? */
10486  /*
10487  * if ((tmp_lsa1.pageid = log_Gl.append.nxio_lsa.pageid - 1) < 0) tmp_lsa1.pageid = 0; */
10488  tmp_lsa1.pageid = 0;
10489  }
10490 
10491  /*
10492  * Flush as much as you can without forcing the current unfinish log
10493  * record.
10494  */
10495  (void) pgbuf_flush_checkpoint (thread_p, &tmp_lsa1, NULL, &tmp_lsa2, NULL);
10496  in_fatal = false;
10497  }
10498  }
10499 
10500  fileio_synchronize_all (thread_p, false);
10501 
10502  fflush (stderr);
10503  fflush (stdout);
10504 
10505 #if defined(CUBRID_DEBUG)
10506  fprintf (stderr, "\n--->>>\n*** LOG FATAL ERROR *** file %s - line %d\n", file_name, lineno);
10507  /* Print out remainder of message */
10508  vfprintf (stderr, fmt, ap);
10509  fprintf (stderr, "\n");
10510 #else /* CUBRID_DEBUG */
10511  fprintf (stderr, "\n--->>>\n*** FATAL ERROR *** \n");
10512 #endif /* CUBRID_DEBUG */
10513 
10514  fprintf (stderr, "%s\n", er_msg ());
10515 
10516  /*
10517  * If error message log is different from terminal or /dev/null..indicate
10518  * that additional information can be found in the error log file
10519  */
10520  msglog = er_get_msglog_filename ();
10521  if (msglog != NULL && strcmp (msglog, "/dev/null") != 0)
10522  {
10523  fprintf (stderr, "Please consult error_log file = %s for additional information\n", msglog);
10524  }
10525 
10526  fflush (stderr);
10527  fflush (stdout);
10528 
10529  if (log_exit == true)
10530  {
10531  fprintf (stderr, "... ABORT/EXIT IMMEDIATELY ...<<<---\n");
10532 
10533 #if defined(SERVER_MODE)
10534  boot_donot_shutdown_server_at_exit ();
10536 #else /* SERVER_MODE */
10537  /*
10538  * The following crap is added to the standalone version to avoid the
10539  * client to continue accessing the database system in presence of
10540  * call on exit functions of the applications.
10541  */
10545 #endif /* SERVER_MODE */
10546 
10547 #if defined(NDEBUG)
10548  exit (EXIT_FAILURE);
10549 #else /* NDEBUG */
10550  /* debugging purpose */
10551  abort ();
10552 #endif /* NDEBUG */
10553  }
10554 }
10555 
10556 #if defined(SERVER_MODE)
10557 /*
10558  * logpb_backup_needed_archive_logs - Backup active log archives
10559  *
10560  * return: NO_ERROR if all OK, ER status otherwise
10561  *
10562  * session(in): The session array which is set as a side effect.
10563  * first_arv_num(in): last arv num to archive (inclusive)
10564  * last_arv_num(in): last arv num to archive (inclusive)
10565  *
10566  * NOTE: Determine which active log records will be required to fully restore
10567  * this backup in the event recovery is needed. This probably includes
10568  * the active log archives as well as at least some portion of the
10569  * log active. Force a log archive of the active log, to insure that we
10570  * have the necessary log records to restore if this backup is "fuzzy".
10571  */
10572 static int
10573 logpb_backup_needed_archive_logs (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session, int first_arv_num,
10574  int last_arv_num)
10575 {
10576  int i;
10577  char logarv_name[PATH_MAX]; /* Archive name */
10578  int error_code = NO_ERROR;
10579 
10580  for (i = first_arv_num; i >= 0 && i <= last_arv_num; i++)
10581  {
10582  /* Backup this archive volume */
10584 
10585  error_code = fileio_backup_volume (thread_p, session, logarv_name, LOG_DBLOG_ARCHIVE_VOLID, -1, false);
10586  if (error_code != NO_ERROR)
10587  {
10588  break;
10589  }
10590  }
10591 
10592  return error_code;
10593 }
10594 #endif /* SERVER_MODE */
10595 
10596 /*
10597  * logpb_remote_ask_user_before_delete_volumes - Remote prompt before arv deletion
10598  *
10599  * return: true if ok to proceed, false if user declines
10600  *
10601  * volpath(in): the pathname to location where deletion will occur
10602  *
10603  * NOTE:Ask the user if it is ok to proceed with a destructive operation, namely
10604  * deleting one or more prior backups.
10605  */
10606 static bool
10608 {
10609  char *ptr1 = NULL, *ptr2 = NULL, *ptr3 = NULL;
10610  char *fullmsg = NULL;
10611  char user_response[FILEIO_MAX_USER_RESPONSE_SIZE];
10612  bool r;
10613 
10617  || asprintf (&fullmsg, "%s%s%s%s", ptr1, ptr2, ptr3, ptr1) < 0)
10618  {
10620  r = false;
10621  goto end;
10622  }
10623 
10624  if (fileio_request_user_response (thread_p, FILEIO_PROMPT_BOOLEAN_TYPE, fullmsg, user_response, NULL, -1, -1, NULL,
10625  -1) != NO_ERROR)
10626  {
10627  r = false;
10628  goto end;
10629  }
10630 
10631  /* process the return */
10632  r = (user_response[0] == '1');
10633 
10634 end:
10635  if (ptr1 != NULL)
10636  {
10637  free (ptr1);
10638  }
10639  if (ptr2 != NULL)
10640  {
10641  free (ptr2);
10642  }
10643  if (ptr3 != NULL)
10644  {
10645  free (ptr3);
10646  }
10647  if (fullmsg != NULL)
10648  {
10649  free (fullmsg);
10650  }
10651 
10652  return r;
10653 }
10654 
10655 /*
10656  * logpb_check_and_reset_temp_lsa -
10657  *
10658  * return:
10659  *
10660  * volid(in):
10661  *
10662  * NOTE:
10663  */
10664 int
10666 {
10667  VPID vpid;
10668  PAGE_PTR pgptr;
10669 
10670  vpid.volid = volid;
10671  vpid.pageid = 0;
10672  pgptr = pgbuf_fix (thread_p, &vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
10673  if (pgptr == NULL)
10674  {
10675  return ER_FAILED;
10676  }
10677 
10678  if (LOG_DBFIRST_VOLID <= volid && xdisk_get_purpose (thread_p, volid) == DB_TEMPORARY_DATA_PURPOSE)
10679  {
10680  pgbuf_reset_temp_lsa (pgptr);
10681  pgbuf_set_dirty (thread_p, pgptr, FREE);
10682  }
10683  else
10684  {
10685  pgbuf_unfix (thread_p, pgptr);
10686  }
10687 
10688  return NO_ERROR;
10689 }
10690 
10691 /*
10692  * logpb_initialize_flush_info - initialize flush information
10693  *
10694  * return: nothing
10695  *
10696  * NOTE:
10697  */
10698 static int
10700 {
10701  int error = NO_ERROR;
10702  LOG_FLUSH_INFO *flush_info = &log_Gl.flush_info;
10703 
10704  if (flush_info->toflush != NULL)
10705  {
10707  }
10708  assert (flush_info->toflush == NULL);
10709 
10710  flush_info->max_toflush = log_Pb.num_buffers - 1;
10711  flush_info->num_toflush = 0;
10712  flush_info->toflush = (LOG_PAGE **) calloc (log_Pb.num_buffers, sizeof (flush_info->toflush));
10713  if (flush_info->toflush == NULL)
10714  {
10716  log_Pb.num_buffers * sizeof (flush_info->toflush));
10717  error = ER_OUT_OF_VIRTUAL_MEMORY;
10718  }
10719 
10720  pthread_mutex_init (&flush_info->flush_mutex, NULL);
10721 
10722  return error;
10723 }
10724 
10725 /*
10726  * logpb_finalize_flush_info - Destroy flush information
10727  *
10728  * return: nothing
10729  *
10730  * NOTE:
10731  */
10732 static void
10734 {
10735 #if defined(SERVER_MODE)
10736  int rv;
10737 #endif /* SERVER_MODE */
10738  LOG_FLUSH_INFO *flush_info = &log_Gl.flush_info;
10739 
10740  if (flush_info->toflush != NULL)
10741  {
10742  rv = pthread_mutex_lock (&flush_info->flush_mutex);
10743  free_and_init (flush_info->toflush);
10744 
10745  flush_info->max_toflush = 0;
10746  flush_info->num_toflush = 0;
10747 
10748  pthread_mutex_unlock (&flush_info->flush_mutex);
10749  pthread_mutex_destroy (&flush_info->flush_mutex);
10750  }
10751 
10752  return;
10753 }
10754 
10755 /*
10756  * logpb_finalize_writer_info - Destroy writer information
10757  *
10758  * return: nothing
10759  *
10760  * NOTE:
10761  */
10762 static void
10764 {
10765 #if defined (SERVER_MODE)
10766  int rv;
10767 #endif
10768  LOGWR_ENTRY *entry, *next_entry;
10769  LOGWR_INFO *writer_info = log_Gl.writer_info;
10770 
10771  if (writer_info->is_init == true)
10772  {
10773  rv = pthread_mutex_lock (&writer_info->wr_list_mutex);
10774  entry = writer_info->writer_list;
10775  while (entry)
10776  {
10777  next_entry = entry->next;
10778  free (entry);
10779  entry = next_entry;
10780  }
10781  writer_info->writer_list = NULL;
10782  writer_info->is_init = false;
10783  pthread_mutex_unlock (&writer_info->wr_list_mutex);
10784 
10785  pthread_mutex_destroy (&writer_info->wr_list_mutex);
10786 
10787  pthread_mutex_destroy (&writer_info->flush_start_mutex);
10788  pthread_cond_destroy (&writer_info->flush_start_cond);
10789 
10790  pthread_mutex_destroy (&writer_info->flush_wait_mutex);
10791  pthread_cond_destroy (&writer_info->flush_wait_cond);
10792 
10793  pthread_mutex_destroy (&writer_info->flush_end_mutex);
10794  pthread_cond_destroy (&writer_info->flush_end_cond);
10795  }
10796 
10797  return;
10798 }
10799 
10800 /*
10801  * logpb_initialize_arv_page_info_table - Initialize archive log page table
10802  *
10803  * return: nothing
10804  *
10805  * NOTE:
10806  */
10807 void
10809 {
10810  memset (&logpb_Arv_page_info_table, 0, sizeof (ARV_LOG_PAGE_INFO_TABLE));
10811  logpb_Arv_page_info_table.rear = -1;
10812 }
10813 
10814 /*
10815  * logpb_initialize_logging_statistics - Initialize logging statistics
10816  *
10817  * return: nothing
10818  *
10819  * NOTE:
10820  */
10821 void
10823 {
10824  memset (&log_Stat, 0, sizeof (LOG_LOGGING_STAT));
10825 }
10826 
10827 /*
10828  * logpb_background_archiving -
10829  *
10830  * return:
10831  *
10832  * NOTE: this function is called by log_initialize_internal only
10833  * (in server startup time)
10834  */
10835 int
10837 {
10838  char log_pgbuf[IO_MAX_PAGE_SIZE * LOGPB_IO_NPAGES + MAX_ALIGNMENT];
10839  char *aligned_log_pgbuf;
10840  LOG_PAGE *log_pgptr;
10841  LOG_PAGEID page_id, last_page_id;
10843  int num_pages = 0;
10844  int vdes;
10845  int error_code = NO_ERROR;
10846  BACKGROUND_ARCHIVING_INFO *bg_arv_info;
10847 
10849 
10850  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
10851  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
10852 
10853  bg_arv_info = &log_Gl.bg_archive_info;
10854  vdes = bg_arv_info->vdes;
10855  if (vdes == NULL_VOLDES)
10856  {
10857  return NO_ERROR;
10858  }
10859 
10860  last_page_id = log_Gl.hdr.chkpt_lsa.pageid - 1;
10861  page_id = bg_arv_info->current_page_id;
10862  phy_pageid = (LOG_PHY_PAGEID) (page_id - bg_arv_info->start_page_id + 1);
10863 
10864  /* Now start dumping the current active pages to archive */
10865  for (; page_id <= last_page_id; page_id += num_pages, phy_pageid += num_pages)
10866  {
10867  num_pages = MIN (LOGPB_IO_NPAGES, (int) (last_page_id - page_id + 1));
10868 
10869  num_pages = logpb_read_page_from_active_log (thread_p, page_id, num_pages, false, log_pgptr);
10870  if (num_pages <= 0)
10871  {
10872  assert (er_errid () != NO_ERROR);
10873  error_code = er_errid ();
10874  goto error;
10875  }
10876 
10877  /* no need to encrypt, it is read as not decrypted (TDE) */
10878  if (fileio_write_pages (thread_p, vdes, (char *) log_pgptr, phy_pageid, num_pages, LOG_PAGESIZE,
10880  {
10881  error_code = ER_LOG_WRITE;
10882  goto error;
10883  }
10884 
10885  bg_arv_info->current_page_id = page_id + num_pages;
10886  }
10887 
10888 error:
10889  if (error_code == ER_LOG_WRITE || error_code == ER_LOG_READ)
10890  {
10891  fileio_dismount (thread_p, bg_arv_info->vdes);
10892  bg_arv_info->vdes = NULL_VOLDES;
10893  bg_arv_info->start_page_id = NULL_PAGEID;
10894  bg_arv_info->current_page_id = NULL_PAGEID;
10895  bg_arv_info->last_sync_pageid = NULL_PAGEID;
10896 
10898  "background archiving error, hdr->start_page_id = %d, hdr->current_page_id = %d, error:%d\n",
10899  bg_arv_info->start_page_id, bg_arv_info->current_page_id, error_code);
10900  }
10901 
10902  log_archive_er_log ("logpb_background_archiving end, hdr->start_page_id = %d, hdr->current_page_id = %d\n",
10903  bg_arv_info->start_page_id, bg_arv_info->current_page_id);
10904 
10905  return error_code;
10906 }
10907 
10908 /*
10909  * logpb_dump_log_header - dump log header
10910  *
10911  * return: Nothing
10912  *
10913  * outfp(in): file descriptor
10914  *
10915  * NOTE:
10916  */
10917 static void
10919 {
10920  fprintf (outfp, "Log Header:\n");
10921 
10922  fprintf (outfp, "\tfirst log page id : %lld\n", (long long int) log_Gl.hdr.fpageid);
10923 
10924  fprintf (outfp, "\tcurrent log append lsa : (%lld|%d)\n", LSA_AS_ARGS (&log_Gl.hdr.append_lsa));
10925 
10926  fprintf (outfp, "\tlast log append lsa : (%lld|%d)\n", LSA_AS_ARGS (&log_Gl.append.prev_lsa));
10927 
10928  fprintf (outfp, "\tlowest lsa which hasn't been written to disk : (%lld|%d)\n",
10929  (long long int) log_Gl.append.get_nxio_lsa ().pageid, (int) log_Gl.append.get_nxio_lsa ().offset);
10930 
10931  fprintf (outfp, "\tcheckpoint lsa : (%lld|%d)\n", LSA_AS_ARGS (&log_Gl.hdr.chkpt_lsa));
10932 
10933  fprintf (outfp, "\tnext archive page id : %lld\n", (long long int) log_Gl.hdr.nxarv_pageid);
10934 
10935  fprintf (outfp, "\tnext archive physical page id : %lld\n", (long long int) log_Gl.hdr.nxarv_phy_pageid);
10936 
10937  fprintf (outfp, "\tnext archive number : %d\n", log_Gl.hdr.nxarv_num);
10938 
10939  fprintf (outfp, "\tlast archive number needed for system crashes : %d\n", log_Gl.hdr.last_arv_num_for_syscrashes);
10940 
10941  fprintf (outfp, "\tlast archive number deleted : %d\n", log_Gl.hdr.last_deleted_arv_num);
10942 
10943  fprintf (outfp, "\tbackup level 0 lsa : (%lld|%d)\n", LSA_AS_ARGS (&log_Gl.hdr.bkup_level0_lsa));
10944 
10945  fprintf (outfp, "\tbackup level 1 lsa : (%lld|%d)\n", LSA_AS_ARGS (&log_Gl.hdr.bkup_level1_lsa));
10946 
10947  fprintf (outfp, "\tbackup level 2 lsa : (%lld|%d)\n", LSA_AS_ARGS (&log_Gl.hdr.bkup_level2_lsa));
10948 
10949  fprintf (outfp, "\tMVCC op lsa : (%lld|%d)\n", LSA_AS_ARGS (&log_Gl.hdr.mvcc_op_log_lsa));
10950 
10951  fprintf (outfp, "\tLast block oldest MVCCID : (%lld)\n", (long long int) log_Gl.hdr.oldest_visible_mvccid);
10952 
10953  fprintf (outfp, "\tLast block newest MVCCID : (%lld)\n", (long long int) log_Gl.hdr.newest_block_mvccid);
10954 }
10955 
10956 /*
10957  * logpb_dump_parameter - dump logging parameter
10958  *
10959  * return: Nothing
10960  *
10961  * outfp(in): file descriptor
10962  *
10963  * NOTE:
10964  */
10965 static void
10966 logpb_dump_parameter (FILE * outfp)
10967 {
10968  fprintf (outfp, "Log Parameters:\n");
10969 
10970  fprintf (outfp, "\tgroup_commit_interval_msec : %d\n",
10972 
10973  fprintf (outfp, "\tasync_commit : %s\n", prm_get_bool_value (PRM_ID_LOG_ASYNC_COMMIT) ? "on" : "off");
10974 }
10975 
10976 /*
10977  * logpb_dump_runtime - dump runtime logging information
10978  *
10979  * return: Nothing
10980  *
10981  * outfp(in): file descriptor
10982  *
10983  * NOTE:
10984  */
10985 static void
10986 logpb_dump_runtime (FILE * outfp)
10987 {
10988  long temp = 1;
10989 
10990  fprintf (outfp, "Log Statistics:\n");
10991 
10992  fprintf (outfp, "\ttotal flush count = %ld\n", log_Stat.flushall_append_pages_call_count);
10993 
10994  fprintf (outfp, "\tgroup commit flush count= %ld\n", log_Stat.gc_flush_count);
10995 
10996  fprintf (outfp, "\tdirect flush count= %ld\n", log_Stat.direct_flush_count);
10997 
10998  fprintf (outfp, "\tgroup commit request count = %ld\n", log_Stat.gc_commit_request_count);
10999 
11000  fprintf (outfp, "\tasync commit request count = %ld\n", log_Stat.async_commit_request_count);
11001 
11002  if (log_Stat.flushall_append_pages_call_count != 0)
11003  {
11004  temp = (log_Stat.flushall_append_pages_call_count - log_Stat.direct_flush_count);
11005  }
11006 
11007  fprintf (outfp, "\tgroup commit grouping rate = %f\n", (double) log_Stat.gc_commit_request_count / temp);
11008 
11009  fprintf (outfp, "\tasync commit grouping rate = %f\n", (double) log_Stat.async_commit_request_count / temp);
11010 
11011  temp = 1;
11012  if (log_Stat.gc_commit_request_count != 0)
11013  {
11014  temp = log_Stat.gc_commit_request_count;
11015  }
11016 
11017  fprintf (outfp, "\tavg group commit wait time = %f\n", log_Stat.gc_total_wait_time / temp);
11018 
11019  fprintf (outfp, "\ttotal commit count = %ld\n", log_Stat.commit_count);
11020 
11021  fprintf (outfp, "\ttotal allocated log pages count = %ld\n", log_Stat.total_append_page_count);
11022 
11023  fprintf (outfp, "\tlog buffer full count = %ld\n", log_Stat.log_buffer_full_count);
11024 
11025  fprintf (outfp, "\tlog buffer flush count by replacement = %ld\n", log_Stat.log_buffer_flush_count_by_replacement);
11026 
11027 }
11028 
11029 /*
11030  * xlogpb_dump_stat - dump logging information
11031  *
11032  * return: Nothing
11033  *
11034  * outfp(in): file descriptor
11035  *
11036  * NOTE:
11037  */
11038 void
11039 xlogpb_dump_stat (FILE * outfp)
11040 {
11041  logpb_dump_parameter (outfp);
11042  logpb_dump_log_header (outfp);
11043  logpb_dump_runtime (outfp);
11044 }
11045 
11046 /*
11047  * logpb_need_wal -
11048  */
11049 bool
11051 {
11052  LOG_LSA nxio_lsa = log_Gl.append.get_nxio_lsa ();
11053 
11054  if (LSA_LE (&nxio_lsa, lsa))
11055  {
11056  return true;
11057  }
11058  else
11059  {
11060  return false;
11061  }
11062 }
11063 
11064 /*
11065  * logpb_backup_level_info_to_string () - format LOG_HDR_BKUP_LEVEL_INFO as string
11066  *
11067  * return: the buffer passed to first argument
11068  *
11069  * buf(out):
11070  * buf_size(in):
11071  * info(in):
11072  */
11073 char *
11074 logpb_backup_level_info_to_string (char *buf, int buf_size, const LOG_HDR_BKUP_LEVEL_INFO * info)
11075 {
11076  char time_str[64];
11077  time_t time_val = (time_t) info->bkup_attime;
11078 
11079  if (time_val == 0)
11080  {
11081  snprintf (buf, buf_size, "time: N/A");
11082  buf[buf_size - 1] = 0;
11083  }
11084  else
11085  {
11086  ctime_r (&time_val, time_str);
11087  /* ctime_r() will padding one '\n' character to buffer, we need truncate it */
11088  time_str[strlen (time_str) - 1] = 0;
11089  snprintf (buf, buf_size, "time: %s", time_str);
11090  buf[buf_size - 1] = 0;
11091  }
11092 
11093  return buf;
11094 }
11095 
11096 /*
11097  * logpb_find_oldest_available_page_id() - return the oldest log pageid
11098  *
11099  * return: log pageid
11100  */
11101 LOG_PAGEID
11103 {
11104  LOG_PAGEID page_id = NULL_PAGEID;
11105  int vdes = NULL_VOLDES;
11106  int arv_num;
11107  LOG_ARV_HEADER *arv_hdr;
11108  char arv_hdr_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_arv_hdr_pgbuf;
11109  LOG_PAGE *arv_hdr_pgptr;
11110  char arv_name[PATH_MAX];
11111 
11113 
11114  LOG_ARCHIVE_CS_ENTER (thread_p);
11115  arv_num = logpb_find_oldest_available_arv_num (thread_p);
11116  if (arv_num < 0)
11117  {
11118  LOG_ARCHIVE_CS_EXIT (thread_p);
11119 
11120  /* return first logical page of active log */
11121  return log_Gl.hdr.nxarv_pageid;
11122  }
11123 
11124  /* before opening a new archive log, close the archive log opened earlier */
11125  if (log_Gl.archive.vdes != NULL_VOLDES)
11126  {
11127  logpb_dismount_log_archive (thread_p);
11128  }
11129 
11130  aligned_arv_hdr_pgbuf = PTR_ALIGN (arv_hdr_pgbuf, MAX_ALIGNMENT);
11131  arv_hdr_pgptr = (LOG_PAGE *) aligned_arv_hdr_pgbuf;
11132 
11134 
11135  vdes = fileio_mount (thread_p, log_Db_fullname, arv_name, LOG_DBLOG_ARCHIVE_VOLID, false, false);
11136  if (vdes != NULL_VOLDES)
11137  {
11138  if (fileio_read (thread_p, vdes, arv_hdr_pgptr, 0, LOG_PAGESIZE) == NULL)
11139  {
11140  fileio_dismount (thread_p, vdes);
11141  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_READ, 3, 0LL, 0LL, arv_name);
11142 
11143  LOG_ARCHIVE_CS_EXIT (thread_p);
11144  return NULL_PAGEID;
11145  }
11146 
11147  arv_hdr = (LOG_ARV_HEADER *) arv_hdr_pgptr->area;
11149  {
11150  if (difftime64 ((time_t) arv_hdr->db_creation, (time_t) log_Gl.hdr.db_creation) != 0)
11151  {
11152  fileio_dismount (thread_p, vdes);
11153 
11155 
11156  LOG_ARCHIVE_CS_EXIT (thread_p);
11157  return NULL_PAGEID;
11158  }
11159  }
11160  page_id = arv_hdr->fpageid;
11161 
11162 #if !defined(NDEBUG)
11163  /* In analysys phase, the page may be corrupted. */
11165  {
11166  logpb_debug_check_log_page (thread_p, arv_hdr_pgptr);
11167  }
11168 #endif
11169 
11170  fileio_dismount (thread_p, vdes);
11171  }
11172 
11173  LOG_ARCHIVE_CS_EXIT (thread_p);
11174  return page_id;
11175 }
11176 
11177 /*
11178  * logpb_find_oldest_available_arv_num() - return oldest archive log number
11179  *
11180  * return: archive log number
11181  */
11182 int
11184 {
11185  char arv_name[PATH_MAX];
11186  int arv_num;
11187  int ret_arv_num = -1;
11188 
11190 
11191  arv_num = log_Gl.hdr.nxarv_num - 1;
11192 
11193  while (arv_num >= 0)
11194  {
11196 
11197  if (fileio_is_volume_exist (arv_name) == true)
11198  {
11199  ret_arv_num = arv_num;
11200 
11201  if (arv_num == 0)
11202  {
11203  break;
11204  }
11205 
11206  arv_num--;
11207  }
11208  else
11209  {
11210  break;
11211  }
11212  }
11213 
11214  return ret_arv_num;
11215 }
11216 
11217 /*
11218  * logpb_remove_all_in_log_path() - Delete all log volumes and files in log path
11219  *
11220  * return: NO_ERROR if all OK, ER status otherwise
11221  */
11222 int
11223 logpb_remove_all_in_log_path (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
11224  const char *prefix_logname)
11225 {
11226  int i, error_code = NO_ERROR;
11227  char vol_fullname[PATH_MAX];
11228  LOG_HEADER disk_hdr;
11229  LOG_HEADER *loghdr = NULL;
11230 
11231  er_clear ();
11232  error_code = logpb_initialize_log_names (thread_p, db_fullname, logpath, prefix_logname);
11233  if (error_code != NO_ERROR)
11234  {
11235  return error_code;
11236  }
11237 
11239  && (log_Gl.append.vdes =
11240  fileio_mount (thread_p, db_fullname, log_Name_active, LOG_DBLOG_ACTIVE_VOLID, true, false)) != NULL_VOLDES)
11241  {
11242  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
11243  LOG_PAGE *log_pgptr;
11244 
11245  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
11246  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
11247 
11248  if (logpb_Initialized == false)
11249  {
11250  error_code = logpb_initialize_pool (thread_p);
11251  if (error_code != NO_ERROR)
11252  {
11253  goto delete_fixed_logs;
11254  }
11255  }
11256  logpb_fetch_header_with_buffer (thread_p, &disk_hdr, log_pgptr);
11257  logpb_finalize_pool (thread_p);
11258  fileio_dismount (thread_p, log_Gl.append.vdes);
11260  loghdr = &disk_hdr;
11261  }
11262 
11263  if (loghdr != NULL)
11264  {
11265  for (i = loghdr->last_deleted_arv_num + 1; i < loghdr->nxarv_num; i++)
11266  {
11268  fileio_unformat (thread_p, vol_fullname);
11269  }
11270  }
11271 
11272 delete_fixed_logs:
11273 
11275  {
11278  }
11279 
11280  fileio_unformat (thread_p, log_Name_active);
11281  fileio_unformat (thread_p, log_Name_info);
11282 
11283  return NO_ERROR;
11284 }
11285 
11286 /*
11287  * logpb_vacuum_reset_log_header_cache () - reset vacuum data cached in log global header.
11288  */
11289 void
11291 {
11292  vacuum_er_log (VACUUM_ER_LOG_VACUUM_DATA, "Reset vacuum info in loghdr (%p)", loghdr);
11293  LSA_SET_NULL (&loghdr->mvcc_op_log_lsa);
11295  loghdr->newest_block_mvccid = MVCCID_NULL;
11296  loghdr->does_block_need_vacuum = false;
11297 }
11298 
11299 /*
11300  * logpb_last_complete_blockid () - get blockid of last completely logged block
11301  *
11302  * return : blockid
11303  */
11306 {
11307  LOG_PAGEID prev_pageid = log_Gl.append.prev_lsa.pageid;
11308  VACUUM_LOG_BLOCKID blockid = vacuum_get_log_blockid (prev_pageid);
11309 
11310  if (blockid < 0)
11311  {
11312  assert (blockid == VACUUM_NULL_LOG_BLOCKID);
11314  return VACUUM_NULL_LOG_BLOCKID;
11315  }
11316 
11317  /* the previous block is the one completed */
11318  return blockid - 1;
11319 }
11320 
11321 /*
11322  * logpb_page_check_corruption - Check whether the log page is corrupted.
11323  * return: error code
11324  * thread_p(in): thread entry
11325  * log_pgptr(in): the log page
11326  * is_page_corrupted(out): true, if the log page is corrupted.
11327  */
11328 int
11329 logpb_page_check_corruption (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, bool * is_page_corrupted)
11330 {
11331  int error_code;
11332  bool has_valid_checksum;
11333 
11334  assert (log_pgptr != NULL && is_page_corrupted != NULL);
11335 
11336  error_code = logpb_page_has_valid_checksum (thread_p, log_pgptr, &has_valid_checksum);
11337  if (error_code != NO_ERROR)
11338  {
11339  return error_code;
11340  }
11341 
11342  *is_page_corrupted = !has_valid_checksum;
11343  return NO_ERROR;
11344 }
11345 
11346 #if !defined(NDEBUG)
11347 void
11348 logpb_debug_check_log_page (THREAD_ENTRY * thread_p, void *log_pgptr_ptr)
11349 {
11350  int err;
11351  bool is_log_page_corrupted;
11352  LOG_PAGE *log_pgptr = (LOG_PAGE *) log_pgptr_ptr;
11353 
11354  assert (log_pgptr != NULL);
11356  {
11357  /* Do not check here since log page size may be not available */
11358  return;
11359  }
11360 
11361  if (log_pgptr->hdr.logical_pageid == -1)
11362  {
11363  /* Skip checking for null logical pageid. */
11364  return;
11365  }
11366 
11367  err = logpb_page_check_corruption (thread_p, log_pgptr, &is_log_page_corrupted);
11368 
11369  assert (err == NO_ERROR && is_log_page_corrupted == false);
11370 }
11371 #endif
11372 
11373 size_t
11375 {
11376  return (size_t) log_Pb.num_buffers * (size_t) LOG_PAGESIZE;
11377 }
11378 
11379 /*
11380  * logpb_set_tde_algorithm () - set tde encryption algorithm to the log page
11381  *
11382  * return : encryption algorithm
11383  * log_pgptr(in) : Log page pointer
11384  */
11387 {
11388  /* exclusive */
11390  && (log_pgptr->hdr.flags & LOG_HDRPAGE_FLAG_ENCRYPTED_ARIA)));
11391 
11392  if (log_pgptr->hdr.flags & LOG_HDRPAGE_FLAG_ENCRYPTED_AES)
11393  {
11394  return TDE_ALGORITHM_AES;
11395  }
11396  else if (log_pgptr->hdr.flags & LOG_HDRPAGE_FLAG_ENCRYPTED_ARIA)
11397  {
11398  return TDE_ALGORITHM_ARIA;
11399  }
11400  else
11401  {
11402  return TDE_ALGORITHM_NONE;
11403  }
11404 }
11405 
11406 /*
11407  * logpb_set_tde_algorithm () - set tde encryption algorithm to the log page
11408  *
11409  * thread_p (in) : Thread entry
11410  * log_pgptr(in) : Log page pointer
11411  * tde_algo (in) : Encryption algorithm
11412  */
11413 void
11414 logpb_set_tde_algorithm (THREAD_ENTRY * thread_p, LOG_PAGE * log_pgptr, const TDE_ALGORITHM tde_algo)
11415 {
11416  assert (tde_Cipher.is_loaded || tde_algo == TDE_ALGORITHM_NONE);
11417  /* clear encrypted flag */
11418  log_pgptr->hdr.flags &= ~LOG_HDRPAGE_FLAG_ENCRYPTED_MASK;
11419 
11420  switch (tde_algo)
11421  {
11422  case TDE_ALGORITHM_AES:
11424  break;
11425  case TDE_ALGORITHM_ARIA:
11427  break;
11428  case TDE_ALGORITHM_NONE:
11429  /* already cleared */
11430  break;
11431  }
11432 }
int logpb_remove_all_in_log_path(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
bool logpb_find_volume_info_exist(void)
unsigned long log_buffer_full_count
Definition: log_impl.h:704
#define ER_LOG_USER_FILE_UNKNOWN
Definition: error_code.h:160
FILEIO_BACKUP_SESSION * fileio_start_backup(THREAD_ENTRY *thread_p, const char *db_full_name_p, INT64 *db_creation_time_p, FILEIO_BACKUP_LEVEL backup_level, LOG_LSA *backup_start_lsa_p, LOG_LSA *backup_checkpoint_lsa_p, FILEIO_BACKUP_RECORD_INFO *all_levels_info_p, FILEIO_BACKUP_SESSION *session_p, FILEIO_ZIP_METHOD zip_method, FILEIO_ZIP_LEVEL zip_level)
Definition: file_io.c:7155
char * PAGE_PTR
LOG_FLUSH_INFO flush_info
Definition: log_impl.h:675
LOG_PAGEID logpb_get_page_id(LOG_PAGE *log_pgptr)
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 int logpb_flush_all_append_pages(THREAD_ENTRY *thread_p)
struct log_rec_header LOG_RECORD_HEADER
Definition: log_record.hpp:141
#define LOG_ARCHIVE_CS_EXIT(thread_p)
Definition: log_impl.h:94
int logpb_initialize_header(THREAD_ENTRY *thread_p, LOG_HEADER *loghdr, const char *prefix_logname, DKNPAGES npages, INT64 *db_creation)
#define pthread_mutex_lock(a)
#define difftime64(time1, time2)
Definition: porting.h:394
static int logpb_get_archive_num_from_info_table(THREAD_ENTRY *thread_p, LOG_PAGEID page_id)
unsigned long gc_flush_count
Definition: log_impl.h:756
int os_rename_file(const char *src_path, const char *dest_path)
Definition: porting.c:1294
static void logpb_start_append(THREAD_ENTRY *thread_p, LOG_RECORD_HEADER *header)
int logpb_get_archive_number(THREAD_ENTRY *thread_p, LOG_PAGEID pageid)
bool pgbuf_has_perm_pages_fixed(THREAD_ENTRY *thread_p)
#define ER_LOG_USER_FILE_INCORRECT_PRIMARY_VOLNAME
Definition: error_code.h:163
char prefix_name[MAXLOGNAME]
#define vacuum_er_log_error(er_log_level, msg,...)
Definition: vacuum.h:69
const VOLID LOG_DBLOG_INFO_VOLID
Definition: log_volids.hpp:45
static void logpb_dump_information(FILE *out_fp)
VOLID logpb_add_volume(const char *db_fullname, VOLID new_volid, const char *new_volfullname, DISK_VOLPURPOSE new_volpurpose)
cubthread::entry * thread_get_thread_entry_info(void)
THREAD_ENTRY * thread_p
Definition: log_writer.h:144
#define NO_ERROR
Definition: error_code.h:46
int logpb_prior_lsa_append_all_list(THREAD_ENTRY *thread_p)
DKNPAGES npages
pthread_mutex_t flush_end_mutex
Definition: log_writer.h:166
void fileio_unformat_and_rename(THREAD_ENTRY *thread_p, const char *vol_label_p, const char *new_label_p)
Definition: file_io.c:2736
static int logpb_compute_page_checksum(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, int *checksum_crc32)
#define __attribute__(X)
Definition: porting.h:36
STATIC_INLINE LOG_BUFFER * logpb_get_log_buffer(LOG_PAGE *log_pg) __attribute__((ALWAYS_INLINE))
VACUUM_LOG_BLOCKID vacuum_get_log_blockid(LOG_PAGEID pageid)
Definition: vacuum.c:5612
static LOG_PRIOR_NODE * prior_lsa_remove_prior_list(THREAD_ENTRY *thread_p)
void LOG_CS_PROMOTE(THREAD_ENTRY *thread_p)
LOG_PRIOR_NODE * prior_list_header
Definition: log_append.hpp:117
const char * verbose_file
Definition: boot_sr.h:98
float db_compatibility
#define ER_LOG_MAYNEED_MEDIA_RECOVERY
Definition: error_code.h:155
const char * log_Db_fullname
Definition: log_global.c:89
void LOG_CS_DEMOTE(THREAD_ENTRY *thread_p)
LOG_BUFFER header_buffer
static int logpb_peek_header_of_active_log_from_backup(THREAD_ENTRY *thread_p, const char *active_log_path, LOG_HEADER *hdr)
#define MSGCAT_LOG_READ_ERROR_DURING_RESTORE
PERF_PAGE_MODE
Definition: perf_monitor.h:197
#define IO_PAGESIZE
TRANTABLE trantable
Definition: log_impl.h:650
static int logpb_start_where_path(const char *to_db_fullname, const char *toext_path, const char **toext_name, char **ext_path, char **alloc_extpath, const char *fileof_vols_and_wherepaths, FILE **where_paths_fp)
#define BO_IS_SERVER_RESTARTED()
Definition: boot_sr.h:84
#define LOG_ESTIMATE_NACTIVE_TRANS
Definition: log_impl.h:112
int num_total_indices
Definition: log_impl.h:581
int logpb_fetch_page(THREAD_ENTRY *thread_p, const LOG_LSA *req_lsa, LOG_CS_ACCESS_MODE access_mode, LOG_PAGE *log_pgptr)
bool logpb_is_smallest_lsa_in_archive(THREAD_ENTRY *thread_p)
bool was_active_log_reset
void logpb_force_flush_header_and_pages(THREAD_ENTRY *thread_p)
int pgbuf_flush_all_unfixed_and_set_lsa_as_null(THREAD_ENTRY *thread_p, VOLID volid)
Definition: page_buffer.c:3116
#define ASSERT_ERROR()
int logpb_copy_page_from_file(THREAD_ENTRY *thread_p, LOG_PAGEID pageid, LOG_PAGE *log_pgptr)
int logpb_initialize_log_names(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
bool LOG_CS_OWN(THREAD_ENTRY *thread_p)
float rel_disk_compatible(void)
pthread_mutex_t gc_mutex
Definition: log_impl.h:319
volatile LOG_PAGEID pageid
const char * fileio_get_zip_level_string(FILEIO_ZIP_LEVEL zip_level)
Definition: file_io.c:10774
LOG_LSA chkpt_redo_lsa
Definition: log_impl.h:660
LOG_LSA bkup_level1_lsa
#define FILEIO_NO_BACKUP_UNITS
Definition: file_io.h:47
LOG_PAGEID start_pageid
LOGPB_APPENDREC_STATUS
void logpb_fetch_header(THREAD_ENTRY *thread_p, LOG_HEADER *hdr)
bool LSA_EQ(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:160
#define ER_LOG_FATAL_ERROR
Definition: error_code.h:777
#define LOGPB_LAST_ACTIVE_PAGE_ID
#define MVCCID_FIRST
pthread_mutex_t flush_start_mutex
Definition: log_writer.h:162
void LSA_COPY(log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:139
#define LOG_APPEND_SETDIRTY_ADD_ALIGN(thread_p, add)
LOG_PAGEID last_append_pageid
Definition: log_impl.h:699
bool prior_is_tde_encrypted(const log_prior_node *node)
static bool logpb_Initialized
int logpb_background_archiving(THREAD_ENTRY *thread_p)
int db_Connect_status
Definition: db_macro.c:88
const char * backuppath
Definition: boot_sr.h:96
#define LOG_IS_PAGE_TDE_ENCRYPTED(log_page_p)
Definition: log_storage.hpp:47
const char * fileio_get_zip_method_string(FILEIO_ZIP_METHOD zip_method)
Definition: file_io.c:10747
int logpb_restore(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname, bo_restart_arg *r_args)
PAGEID DKNPAGES
void logpb_flush_log_for_wal(THREAD_ENTRY *thread_p, const LOG_LSA *lsa_ptr)
#define FILEIO_FIRST_BACKUP_VOL_INFO
Definition: file_io.h:57
unsigned long total_flush_count_by_trans
Definition: log_impl.h:714
#define ER_LOG_PREFIX_NAME_IS_TOO_LONG
Definition: error_code.h:143
void * fileio_read(THREAD_ENTRY *thread_p, int vol_fd, void *io_page_p, PAGEID page_id, size_t page_size)
Definition: file_io.c:3950
#define ER_LOG_PAGE_CORRUPTED
Definition: error_code.h:140
#define LOGAREA_SIZE
Definition: log_impl.h:116
#define VACUUM_ER_LOG_ARCHIVES
Definition: vacuum.h:57
INT64 last_writer_elapsed_time
Definition: log_writer.h:174
LOG_RECORD_HEADER log_header
Definition: log_append.hpp:92
LOG_LSA sysop_start_postpone_lsa
Definition: log_impl.h:448
LOG_PB_GLOBAL_DATA log_Pb
#define CUBRID_MAGIC_LOG_ACTIVE
#define DISK_VOLPURPOSE
int fileio_get_next_restore_file(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p, char *file_name_p, VOLID *vol_id_p)
Definition: file_io.c:9960
#define ER_FAILED
Definition: error_code.h:47
void logpb_invalid_all_append_pages(THREAD_ENTRY *thread_p)
const int LOG_SYSTEM_TRAN_INDEX
#define LOG_HDRPAGE_FLAG_ENCRYPTED_MASK
Definition: log_storage.hpp:45
ARV_PAGE_INFO page_info[ARV_PAGE_INFO_TABLE_SIZE]
#define CUBRID_MAGIC_LOG_ARCHIVE
LOG_GLOBAL log_Gl
LOG_HEADER hdr
Definition: log_impl.h:653
#define LOG_ESTIMATE_NOBJ_LOCKS
Definition: log_impl.h:113
void logpb_set_tde_algorithm(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, const TDE_ALGORITHM tde_algo)
#define ALWAYS_INLINE
#define NULL_TRANID
const char * boot_db_name(void)
Definition: boot_sr.c:459
VOLID fileio_find_next_perm_volume(THREAD_ENTRY *thread_p, VOLID volid)
Definition: file_io.c:6410
LOGPB_PARTIAL_APPEND partial_append
bool logpb_need_wal(const LOG_LSA *lsa)
int fileio_finish_restore(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:9683
CLIENTIDS last_writer_client_info
Definition: log_writer.h:173
bool dwb_is_created(void)
FILEIO_BACKUP_SESSION * fileio_start_restore(THREAD_ENTRY *thread_p, const char *db_full_name_p, char *backup_source_p, INT64 match_db_creation_time, PGLENGTH *db_io_page_size_p, float *db_compatibility_p, FILEIO_BACKUP_SESSION *session_p, FILEIO_BACKUP_LEVEL level, bool is_authenticate, INT64 match_backup_creation_time, const char *restore_verbose_file_path, bool is_new_vol_path)
Definition: file_io.c:9264
time_t stopat
Definition: boot_sr.h:95
LOG_HDRPAGE hdr
Definition: log_storage.hpp:84
static bool logpb_check_if_exists(const char *fname, char *first_vol)
int fileio_skip_restore_volume(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:10559
#define TRAN_DEFAULT_ISOLATION_LEVEL()
Definition: dbtran_def.h:58
const char * vlabel
Definition: file_io.h:329
bool fileio_is_volume_exist_and_file(const char *vol_label_p)
Definition: file_io.c:5132
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
MVCCID oldest_visible_mvccid
int fileio_restore_volume(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p, char *to_vol_label_p, char *verbose_to_vol_label_p, char *prev_vol_label_p, FILEIO_RESTORE_PAGE_BITMAP *page_bitmap, bool is_remember_pages)
Definition: file_io.c:10235
int disk_set_link(THREAD_ENTRY *thread_p, INT16 volid, INT16 next_volid, const char *next_volext_fullname, bool logchange, DISK_FLUSH_TYPE flush)
Definition: disk_manager.c:969
LOG_LSA forw_lsa
Definition: log_record.hpp:146
unsigned int lock_get_number_object_locks(void)
char name[PATH_MAX]
Definition: file_io.h:330
#define CUBRID_MAGIC_LOG_INFO
#define PAGEID_MAX
int disk_set_checkpoint(THREAD_ENTRY *thread_p, INT16 volid, const LOG_LSA *log_chkpt_lsa)
LOG_LSA prev_tranlsa
Definition: log_record.hpp:144
int logpb_find_oldest_available_arv_num(THREAD_ENTRY *thread_p)
static LOG_PAGE * logpb_locate_page(THREAD_ENTRY *thread_p, LOG_PAGEID pageid, PAGE_FETCH_MODE fetch_mode)
#define ASSERT_ERROR_AND_SET(error_code)
PAGEID LOG_PHY_PAGEID
void thread_sleep(double millisec)
#define ER_BO_UNSORTED_VOLINFO
Definition: error_code.h:693
void logtb_clear_tdes(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
#define ER_LOG_CHECKPOINT_FINISHED
Definition: error_code.h:1222
static void logpb_append_archives_removed_to_log_info(int first, int last, const char *info_reason)
LOG_PAGE * loghdr_pgptr
Definition: log_impl.h:672
#define assert_release(e)
Definition: error_manager.h:96
void logpb_fetch_header_with_buffer(THREAD_ENTRY *thread_p, LOG_HEADER *hdr, LOG_PAGE *log_pgptr)
#define REL_MAX_RELEASE_LENGTH
pthread_mutex_t wr_list_mutex
Definition: log_writer.h:160
void thread_wakeup_already_had_mutex(cubthread::entry *thread_p, thread_resume_suspend_status resume_reason)
void pgbuf_set_dirty(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, bool free_page)
Definition: page_buffer.c:4280
int num_assigned_indices
Definition: log_impl.h:582
enum log_setdirty LOG_SETDIRTY
Definition: log_impl.h:283
INT64 log_get_clock_msec(void)
STATIC_INLINE int logpb_get_log_buffer_index(LOG_PAGEID log_pageid) __attribute__((ALWAYS_INLINE))
void LOG_CS_ENTER(THREAD_ENTRY *thread_p)
unsigned long gc_commit_request_count
Definition: log_impl.h:750
#define LOG_IS_GROUP_COMMIT_ACTIVE()
Definition: log_impl.h:119
char user_name[LOG_USERNAME_MAX]
Definition: log_record.hpp:355
LOG_PRIOR_NODE * prior_list_tail
Definition: log_append.hpp:118
INT16 VOLID
#define MSGCAT_LOG_LOGINFO_COMMENT_MANY_ARCHIVES_NONEEDED
#define MVCCID_NULL
char log_Name_active[PATH_MAX]
Definition: log_global.c:90
#define ER_IO_MOUNT_LOCKED
Definition: error_code.h:60
const VOLID LOG_DBLOG_ACTIVE_VOLID
Definition: log_volids.hpp:49
unsigned long commit_count
Definition: log_impl.h:733
LOG_PAGE * log_page_record_header
VOLID xboot_find_last_permanent(THREAD_ENTRY *thread_p)
Definition: boot_sr.c:377
static int logpb_append_next_record(THREAD_ENTRY *thread_p, LOG_PRIOR_NODE *ndoe)
LOG_LSA tail_lsa
Definition: log_impl.h:473
void logpb_decache_archive_info(THREAD_ENTRY *thread_p)
static void logpb_dump_to_flush_page(FILE *out_fp)
static ARV_LOG_PAGE_INFO_TABLE logpb_Arv_page_info_table
#define ER_BO_FULL_DATABASE_NAME_IS_TOO_LONG
Definition: error_code.h:178
void fileio_make_log_archive_temp_name(char *log_archive_temp_name_p, const char *log_path_p, const char *db_name_p)
Definition: file_io.c:5793
struct timeval TSCTIMEVAL
Definition: tsc_timer.h:40
void logpb_page_get_first_null_block_lsa(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, LOG_LSA *first_null_block_lsa)
#define ER_LOG_FLUSHING_UNUPDATABLE
Definition: error_code.h:771
double use_append_page_sec
Definition: log_impl.h:701
#define LOGPB_HEADER_PAGE_ID
#define ER_LOG_MOUNT_FAIL
Definition: error_code.h:141
LOG_GROUP_COMMIT_INFO group_commit_info
Definition: log_impl.h:678
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
int pgbuf_flush_all_unfixed(THREAD_ENTRY *thread_p, VOLID volid)
Definition: page_buffer.c:3099
LOG_PAGE * logpage
void tsc_elapsed_time_usec(TSCTIMEVAL *tv, TSC_TICKS end_tick, TSC_TICKS start_tick)
Definition: tsc_timer.c:101
LOG_PAGEID fpageid
void logpb_set_dirty(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr)
LOG_LSA atomic_sysop_start_lsa
Definition: log_record.hpp:364
pthread_cond_t flush_start_cond
Definition: log_writer.h:161
int32_t pageid
Definition: dbtype_def.h:879
int logpb_backup(THREAD_ENTRY *thread_p, int num_perm_vols, const char *allbackup_path, FILEIO_BACKUP_LEVEL backup_level, bool delete_unneeded_logarchives, const char *backup_verbose_file_path, int num_threads, FILEIO_ZIP_METHOD zip_method, FILEIO_ZIP_LEVEL zip_level, int skip_activelog, int sleep_msecs, bool separate_keys)
void fileio_remove_all_backup(THREAD_ENTRY *thread_p, int start_level)
Definition: file_io.c:7446
pthread_cond_t flush_wait_cond
Definition: log_writer.h:163
#define LSA_AS_ARGS(lsa_ptr)
Definition: log_lsa.hpp:78
#define VACUUM_NULL_LOG_BLOCKID
int er_errid(void)
static bool logpb_is_any_dirty(THREAD_ENTRY *thread_p)
LOG_PRIOR_NODE * prior_lsa_alloc_and_copy_data(THREAD_ENTRY *thread_p, LOG_RECTYPE rec_type, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int ulength, const char *udata, int rlength, const char *rdata)
Definition: log_append.cpp:273
const VOLID LOG_DBLOG_BKUPINFO_VOLID
Definition: log_volids.hpp:47
#define LOG_MAX_LOGINFO_LINE
const char * log_state_string(TRAN_STATE state)
Definition: log_comm.c:125
#define bool
Definition: dbi_compat.h:31
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
void crypt_crc32(const char *src, int src_len, int *dest)
Definition: crypt_opfunc.c:672
bool logtb_get_check_interrupt(THREAD_ENTRY *thread_p)
int fileio_clear_backup_info_level(int level, bool is_dealloc, int which_bkvinf)
Definition: file_io.c:11245
#define ER_TM_GET_STAT_FAIL
Definition: error_code.h:1099
#define LOGPB_PHYSICAL_HEADER_PAGE_ID
std::mutex prior_lsa_mutex
Definition: log_append.hpp:125
static void logpb_dump_runtime(FILE *outfp)
static void logpb_dismount_log_archive(THREAD_ENTRY *thread_p)
#define MSGCAT_LOG_INPUT_RANGE_ERROR
bool LSA_LT(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:174
int logpb_create_volume_info(const char *db_fullname)
static int logpb_copy_page(THREAD_ENTRY *thread_p, LOG_PAGEID pageid, LOG_CS_ACCESS_MODE access_mode, LOG_PAGE *log_pgptr)
#define er_log_debug(...)
TDE_ALGORITHM logpb_get_tde_algorithm(const LOG_PAGE *log_pgptr)
#define LOG_PAGE_INIT_VALUE
#define ER_BO_CANNOT_CREATE_LINK
Definition: error_code.h:971
LOG_PAGE * logpb_create_page(THREAD_ENTRY *thread_p, LOG_PAGEID pageid)
char log_Name_removed_archive[PATH_MAX]
Definition: log_global.c:95
const VOLID LOG_DBCOPY_VOLID
Definition: log_volids.hpp:55
LOG_LSA append_lsa
#define MSGCAT_LOG_LOGINFO_KEYWORD_ARCHIVE
static void logpb_initialize_log_buffer(LOG_BUFFER *log_buffer_p, LOG_PAGE *log_pg)
#define MSGCAT_LOG_LOGINFO_ACTIVE
char * fileio_get_volume_label_by_fd(int vol_fd, bool is_peek)
Definition: file_io.c:6254
bool has_logging_been_skipped
void fileio_make_temp_log_files_from_backup(char *temp_log_name, VOLID to_volid, FILEIO_BACKUP_LEVEL level, const char *base_log_name)
Definition: file_io.c:5726
FILEIO_BACKUP_HEADER * bkuphdr
Definition: file_io.h:343
LOGWR_STATUS status
Definition: log_writer.h:147
bool appending_page_tde_encrypted
Definition: log_append.hpp:80
static int logpb_update_backup_volume_info(const char *bkupinfo_file_name)
char * fileio_get_directory_path(char *path_p, const char *full_name_p)
Definition: file_io.c:5567
int logpb_set_page_checksum(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr)
#define pgbuf_invalidate_all(thread_p, volid)
Definition: page_buffer.h:286
void _er_log_debug(const char *file_name, const int line_no, const char *fmt,...)
#define NULL_VOLDES
Definition: file_io.h:44
BOOT_SERVER_STATUS boot_Server_status
Definition: boot_sr.c:148
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
bool logpb_is_page_in_archive(LOG_PAGEID pageid)
static void logpb_write_toflush_pages_to_archive(THREAD_ENTRY *thread_p)
void log_wakeup_log_flush_daemon()
Definition: log_manager.c:9715
const char * fileio_rename(VOLID vol_id, const char *old_label_p, const char *new_label_p)
Definition: file_io.c:5070
char log_Name_volinfo[PATH_MAX]
Definition: log_global.c:93
static int logpb_append_prior_lsa_list(THREAD_ENTRY *thread_p, LOG_PRIOR_NODE *list)
#define FILEIO_INITIAL_BACKUP_UNITS
Definition: file_io.h:46
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
#define ER_LOG_DBBACKUP_FAIL
Definition: error_code.h:159
void * fileio_read_pages(THREAD_ENTRY *thread_p, int vol_fd, char *io_pages_p, PAGEID page_id, int num_pages, size_t page_size)
Definition: file_io.c:4227
int fileio_read_backup_info_entries(FILE *fp, int which_bkvinf)
Definition: file_io.c:11065
unsigned long last_commit_count_while_using_a_page
Definition: log_impl.h:740
void fileio_page_bitmap_list_init(FILEIO_RESTORE_PAGE_BITMAP_LIST *page_bitmap_list)
Definition: file_io.c:11601
const char * er_get_msglog_filename(void)
#define ER_IO_WRITE_OUT_OF_SPACE
Definition: error_code.h:64
LOG_LSA back_lsa
Definition: log_record.hpp:145
LOG_PRIOR_NODE * prior_flush_list_header
Definition: log_append.hpp:123
static int logpb_remove_archive_logs_internal(THREAD_ENTRY *thread_p, int first, int last, const char *info_reason)
void THREAD_ENTRY
double total_flush_hdr_sec_by_LFT
Definition: log_impl.h:727
#define ER_BO_CANNOT_CREATE_VOL
Definition: error_code.h:184
static void logpb_fatal_error_internal(THREAD_ENTRY *thread_p, bool log_exit, bool need_flush, const char *file_name, const int lineno, const char *fmt, va_list ap)
#define NULL_PAGEID
static int logpb_page_has_valid_checksum(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, bool *has_valid_checksum)
int fileio_symlink(const char *src_p, const char *dest_p, int overwrite)
Definition: file_io.c:11503
FILEIO_WRITE_MODE
Definition: file_io.h:164
#define ER_TDE_ENCRYPTION_LOGPAGE_ERORR_AND_OFF_TDE
Definition: error_code.h:1623
LOG_LSA tail_topresult_lsa
Definition: log_impl.h:480
LOG_HDR_BKUP_LEVEL_INFO bkinfo[FILEIO_BACKUP_UNDEFINED_LEVEL]
#define TR_TABLE_CS_ENTER(thread_p)
Definition: log_impl.h:88
const size_t MAXLOGNAME
Definition: log_storage.hpp:88
bool flush_completed
Definition: log_writer.h:168
#define ER_BO_VOLUME_EXISTS
Definition: error_code.h:185
#define MSGCAT_SET_LOG
#define ER_LOG_READ
Definition: error_code.h:137
static void logpb_append_data(THREAD_ENTRY *thread_p, int length, const char *data)
#define ER_LOG_NAME_IS_TOO_LONG
Definition: error_code.h:142
INT64 db_creation
int logpb_initialize_pool(THREAD_ENTRY *thread_p)
#define FREE(PTR)
Definition: cas_common.h:56
static int logpb_verify_length(const char *db_fullname, const char *log_path, const char *log_prefix)
void LOG_RESET_PREV_LSA(const LOG_LSA *lsa)
Definition: log_append.cpp:137
REL_COMPATIBILITY
LOG_RECTYPE type
Definition: log_record.hpp:148
LOG_LSA prior_lsa_next_record(THREAD_ENTRY *thread_p, LOG_PRIOR_NODE *node, log_tdes *tdes)
INTL_CODESET lang_charset(void)
static int logpb_copy_volume(THREAD_ENTRY *thread_p, VOLID from_volid, const char *tonew_volname, INT64 *db_creation, LOG_LSA *vol_chkpt_lsa)
volatile LOG_PHY_PAGEID phy_pageid
int disk_set_creation(THREAD_ENTRY *thread_p, INT16 volid, const char *new_vol_fullname, const INT64 *new_dbcreation, const LOG_LSA *new_chkptlsa, bool logchange, DISK_FLUSH_TYPE flush)
Definition: disk_manager.c:850
void fileio_page_bitmap_list_add(FILEIO_RESTORE_PAGE_BITMAP_LIST *page_bitmap_list, FILEIO_RESTORE_PAGE_BITMAP *page_bitmap)
Definition: file_io.c:11684
const char * tde_get_algorithm_name(TDE_ALGORITHM tde_algo)
Definition: tde.c:1694
const char * boot_db_full_name()
Definition: boot_sr.c:470
void boot_donot_shutdown_client_at_exit(void)
Definition: boot_cl.c:1485
#define MSGCAT_LOG_LOGINFO_ARCHIVE
char * data_header
Definition: log_append.hpp:99
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
LOG_ARV_HEADER hdr
db_client_type client_type
unsigned long total_append_page_count
Definition: log_impl.h:697
static void logpb_archive_active_log(THREAD_ENTRY *thread_p)
int fileio_get_volume_max_suffix(void)
Definition: file_io.c:5604
void LOG_CS_ENTER_READ_MODE(THREAD_ENTRY *thread_p)
char * fileio_get_volume_label(VOLID vol_id, bool is_peek)
Definition: file_io.c:6182
static bool logpb_is_dirty(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr)
void logpb_dump_checkpoint_trans(FILE *out_fp, int length, void *data)
const VOLID LOG_DBLOG_ARCHIVE_VOLID
Definition: log_volids.hpp:53
int fileio_add_volume_to_backup_info(const char *name_p, FILEIO_BACKUP_LEVEL level, int unit_num, int which_bkvinf)
Definition: file_io.c:10954
PAGE_FETCH_MODE
Definition: page_buffer.h:160
unsigned long last_flush_count_by_trans
Definition: log_impl.h:712
#define MSGCAT_LOG_DELETE_BKVOLS
LOG_LSA start_lsa
Definition: log_append.hpp:93
const char * fileio_get_base_file_name(const char *full_name_p)
Definition: file_io.c:5533
#define assert(x)
void logpb_force_flush_pages(THREAD_ENTRY *thread_p)
static void logpb_initialize_backup_info(LOG_HEADER *loghdr)
LOG_RECVPHASE rcv_phase
Definition: log_impl.h:662
LOG_APPEND_INFO append
Definition: log_impl.h:651
Definition: log_writer.h:142
FILEIO_ZIP_LEVEL
Definition: file_io.h:113
#define ER_LOG_USER_FILE_UNORDERED_ENTRIES
Definition: error_code.h:162
const VOLID LOG_DBFIRST_VOLID
Definition: log_volids.hpp:38
std::int64_t VACUUM_LOG_BLOCKID
Definition: log_storage.hpp:91
const VOLID LOG_DBVOLINFO_VOLID
Definition: log_volids.hpp:43
void logpb_checkpoint_trans(LOG_INFO_CHKPT_TRANS *chkpt_entries, log_tdes *tdes, int &ntrans, int &ntops, LOG_LSA &smallest_lsa)
static bool logpb_is_log_active_from_backup_useful(THREAD_ENTRY *thread_p, const char *active_log_path, const char *db_full_name)
unsigned long flush_hdr_call_count
Definition: log_impl.h:723
#define ER_TM_IS_NOT_WRITEABLE
Definition: error_code.h:1100
LOG_PAGE * logpb_fetch_from_archive(THREAD_ENTRY *thread_p, LOG_PAGEID pageid, LOG_PAGE *log_pgptr, int *ret_arv_num, LOG_ARV_HEADER *ret_arv_hdr, bool is_fatal)
char log_Name_info[PATH_MAX]
Definition: log_global.c:91
LOG_PAGEID fpageid
char * disk_get_link(THREAD_ENTRY *thread_p, INT16 volid, INT16 *next_volid, char *next_volext_fullname)
TDE_ALGORITHM
Definition: tde.h:71
#define MSGCAT_LOG_BACKUP_HALTED_BY_USER
LOG_PRIOR_NODE * next
Definition: log_append.hpp:107
#define ASSERT_ALIGN(ptr, alignment)
LOG_PAGE * log_pgptr
Definition: log_append.hpp:78
#define ER_LOG_BKUP_DUPLICATE_REQUESTS
Definition: error_code.h:1034
static int logpb_next_where_path(const char *to_db_fullname, const char *toext_path, const char *ext_name, char *ext_path, const char *fileof_vols_and_wherepaths, FILE *where_paths_fp, int num_perm_vols, VOLID volid, char *from_volname, char *to_volname)
void set_nxio_lsa(const LOG_LSA &next_io_lsa)
Definition: log_append.cpp:112
int prm_get_integer_value(PARAM_ID prm_id)
void logpb_invalidate_pool(THREAD_ENTRY *thread_p)
void event_log_log_flush_thr_wait(THREAD_ENTRY *thread_p, int flush_count, clientids *client_info, int flush_time, int flush_wait_time, int writer_time)
Definition: event_log.c:446
static int logpb_check_stop_at_time(FILEIO_BACKUP_SESSION *session, time_t stop_at, time_t backup_time)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
LOG_PAGEID end_pageid
LOG_PAGE * logpb_fetch_start_append_page_new(THREAD_ENTRY *thread_p)
#define STATIC_INLINE
LOG_PAGEID logpb_checkpoint(THREAD_ENTRY *thread_p)
DISK_VOLPURPOSE xdisk_get_purpose(THREAD_ENTRY *thread_p, VOLID volid)
#define ER_LOG_BACKUP_LEVEL_NOGAPS
Definition: error_code.h:956
LOG_LSA undo_nxlsa
Definition: log_impl.h:474
void fileio_close(int vol_fd)
Definition: file_io.c:2078
void logpb_dump_log_page_area(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, int offset, int length)
PGLENGTH db_logpagesize
#define CUBRID_MAGIC_MAX_LENGTH
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
void LOG_CS_EXIT(THREAD_ENTRY *thread_p)
void LOG_RESET_APPEND_LSA(const LOG_LSA *lsa)
Definition: log_append.cpp:129
void fileio_page_bitmap_list_destroy(FILEIO_RESTORE_PAGE_BITMAP_LIST *page_bitmap_list)
Definition: file_io.c:11726
#define MSGCAT_LOG_LOGINFO_COMMENT
TDE_CIPHER tde_Cipher
Definition: tde.c:69
unsigned long last_commit_count_in_flush_pages
Definition: log_impl.h:745
int last_deleted_arv_num
void fileio_abort_backup(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p, bool does_unformat_bk)
Definition: file_io.c:7052
int ha_server_state
LOG_LSA prior_lsa_next_record_with_lock(THREAD_ENTRY *thread_p, LOG_PRIOR_NODE *node, log_tdes *tdes)
#define LOGPB_ACTIVE_NPAGES
char area[1]
Definition: log_storage.hpp:85
void xlogpb_dump_stat(FILE *outfp)
void logpb_remove_archive_logs(THREAD_ENTRY *thread_p, const char *info_reason)
bool LSA_LE(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:167
PGLENGTH logpb_find_header_parameters(THREAD_ENTRY *thread_p, const bool force_read_log_header, const char *db_fullname, const char *logpath, const char *prefix_logname, PGLENGTH *io_page_size, PGLENGTH *log_page_size, INT64 *creation_time, float *db_compatibility, int *db_charset)
bool log_is_log_flush_daemon_available()
Definition: log_manager.c:9730
#define ER_LOG_WRITE_OUT_OF_SPACE
Definition: error_code.h:139
int logpb_check_exist_any_volumes(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname, char *first_vol, bool *is_exist)
#define LOGPB_FIND_BUFPTR(bufid)
void tde_make_keys_file_fullname(char *keys_vol_fullname, const char *db_full_name, bool ignore_parm)
Definition: tde.c:492
FILEIO_RESTORE_PAGE_BITMAP * fileio_page_bitmap_list_find(FILEIO_RESTORE_PAGE_BITMAP_LIST *page_bitmap_list, int vol_id)
Definition: file_io.c:11653
LOG_PAGEID logical_pageid
Definition: log_storage.hpp:65
#define LOGPB_AT_NEXT_ARCHIVE_PAGE_ID(pageid)
int * unav_archives
void log_wakeup_remove_log_archive_daemon()
LOG_LSA savept_lsa
Definition: log_impl.h:478
int logpb_read_page_from_file(THREAD_ENTRY *thread_p, LOG_PAGEID pageid, LOG_CS_ACCESS_MODE access_mode, LOG_PAGE *log_pgptr)
char log_Prefix[PATH_MAX]
Definition: log_global.c:87
#define VACUUM_ER_LOG_MASTER
Definition: vacuum.h:54
int ha_file_status
int logpb_rename_all_volumes_files(THREAD_ENTRY *thread_p, VOLID num_perm_vols, const char *to_db_fullname, const char *to_logpath, const char *to_prefix_logname, const char *toext_path, const char *fileof_vols_and_renamepaths, bool extern_rename, bool force_delete)
char keys_file_path[PATH_MAX]
Definition: boot_sr.h:107
#define ER_LOG_BACKUP_CS_ENTER
Definition: error_code.h:1365
short volid
Definition: dbtype_def.h:880
FILE * verbose_fp
Definition: file_io.h:435
int asprintf(char **ptr, const char *format,...)
Definition: porting.c:973
LOG_LSA posp_nxlsa
Definition: log_impl.h:476
void fileio_dismount(THREAD_ENTRY *thread_p, int vol_fd)
Definition: file_io.c:3134
bool skip_flush
Definition: log_writer.h:167
int logpb_delete(THREAD_ENTRY *thread_p, VOLID num_perm_vols, const char *db_fullname, const char *logpath, const char *prefix_logname, bool force_delete)
#define DB_MAX_PATH_LENGTH
LOG_PAGE * logpb_create_header_page(THREAD_ENTRY *thread_p)
static bool logpb_is_archive_available(THREAD_ENTRY *thread_p, int arv_num)
const char * rel_name(void)
pthread_mutex_t flush_wait_mutex
Definition: log_writer.h:164
std::int64_t pageid
Definition: log_lsa.hpp:36
static void logpb_finalize_flush_info(void)
int fileio_synchronize_all(THREAD_ENTRY *thread_p, bool is_include)
Definition: file_io.c:4618
LOG_PAGEID nxarv_pageid
DKNPAGES chkpt_every_npages
Definition: log_impl.h:661
FILEIO_BACKUP_SESSION * fileio_finish_backup(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:7336
void log_append_init_zip()
Definition: log_append.cpp:185
INT64 LOG_PAGEID
static void logpb_dump_log_header(FILE *outfp)
#define MSGCAT_LOG_DATABASE_BACKUP_WAS_TAKEN
LOG_LSA rcv_phase_lsa
Definition: log_impl.h:663
#define NULL
Definition: freelistheap.h:34
LOG_ARCHIVES archive
Definition: log_impl.h:654
#define CTIME_MAX
Definition: porting.h:72
#define strncpy_bufsize(buf, str)
Definition: porting.h:340
LOGWR_ENTRY * writer_list
Definition: log_writer.h:159
const char * er_msg(void)
void fileio_make_removed_log_archive_name(char *log_archive_name_p, const char *log_path_p, const char *db_name_p)
Definition: file_io.c:5777
#define LOG_HDRPAGE_FLAG_ENCRYPTED_AES
Definition: log_storage.hpp:42
double last_flush_sec_by_trans
Definition: log_impl.h:716
static char * dbname
void tsc_getticks(TSC_TICKS *tck)
Definition: tsc_timer.c:81
if(extra_options)
Definition: dynamic_load.c:958
STATIC_INLINE bool perfmon_is_perf_tracking(void) __attribute__((ALWAYS_INLINE))
#define TIME_SIZE_OF_DUMP_LOG_INFO
Definition: log_comm.h:31
#define FILEIO_MAX_USER_RESPONSE_SIZE
Definition: file_io.h:50
bool log_is_in_crash_recovery(void)
Definition: log_manager.c:476
static bool logpb_Logging
#define vacuum_er_log(er_log_level, msg,...)
Definition: vacuum.h:65
bool vacuum_is_safe_to_remove_archives(void)
Definition: vacuum.c:5650
int logtb_define_trantable_log_latch(THREAD_ENTRY *thread_p, int num_expected_tran_indices)
char current_path[PATH_MAX]
Definition: file_io.h:333
DKNPAGES xdisk_get_total_numpages(THREAD_ENTRY *thread_p, VOLID volid)
static int success()
bool LSA_ISNULL(const log_lsa *lsa_ptr)
Definition: log_lsa.hpp:153
int util_compare_filepath(const char *file1, const char *file2)
Definition: util_func.c:111
int logtb_reflect_global_unique_stats_to_btree(THREAD_ENTRY *thread_p)
LOG_LSA bkup_level2_lsa
#define LOGPB_IS_ARCHIVE_PAGE(pageid)
#define MSGCAT_LOG_LOGINFO_COMMENT_ARCHIVE_NONEEDED
#define ER_LOG_MAX_ARCHIVES_HAS_BEEN_EXCEEDED
Definition: error_code.h:736
void fileio_finalize_backup_info(int which_bkvinf)
Definition: file_io.c:11143
#define LOG_HDRPAGE_FLAG_ENCRYPTED_ARIA
Definition: log_storage.hpp:43
#define err(fd,...)
Definition: porting.h:431
int last_arv_num_for_syscrashes
pthread_cond_t flush_end_cond
Definition: log_writer.h:165
#define pgbuf_fix(thread_p, vpid, fetch_mode, requestmode, condition)
Definition: page_buffer.h:255
void thread_lock_entry(cubthread::entry *thread_p)
LOG_LSA head_lsa
Definition: log_impl.h:472
FILEIO_BACKUP_LEVEL level
Definition: file_io.h:298
PGLENGTH offset
Definition: log_storage.hpp:66
int logpb_flush_page(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr)
void log_append_final_zip()
Definition: log_append.cpp:232
MVCCID newest_block_mvccid
#define MSGCAT_LOG_LOGINFO_COMMENT_UNUSED_ARCHIVE_NAME
char log_Name_bkupinfo[PATH_MAX]
Definition: log_global.c:92
void logpb_flush_pages_direct(THREAD_ENTRY *thread_p)
#define NULL_OFFSET
#define CEIL_PTVDIV(dividend, divisor)
Definition: memory_alloc.h:50
void logpb_flush_header(THREAD_ENTRY *thread_p)
char * logpb_backup_level_info_to_string(char *buf, int buf_size, const LOG_HDR_BKUP_LEVEL_INFO *info)
LOG_LSA last_chkpt_lsa
Definition: file_io.h:327
char * db_name
#define ER_LOG_NOTIN_ARCHIVE
Definition: error_code.h:156
CLIENTIDS client
Definition: log_impl.h:484
LOG_PRIOR_LSA_INFO prior_info
Definition: log_impl.h:652
char log_Name_bg_archive[PATH_MAX]
Definition: log_global.c:94
int pgbuf_flush_all(THREAD_ENTRY *thread_p, VOLID volid)
Definition: page_buffer.c:3083
void er_set_with_oserror(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
#define detailed_er_log(...)
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
#define MSGCAT_CATALOG_CUBRID
char * LOG_APPEND_PTR()
Definition: log_append.cpp:145
void logpb_finalize_pool(THREAD_ENTRY *thread_p)
void fileio_make_log_active_name(char *log_active_name_p, const char *log_path_p, const char *db_name_p)
Definition: file_io.c:5707
#define ER_LOG_USER_FILE_WITHOUT_ENOUGH_ENTRIES
Definition: error_code.h:161
int timeval_to_timespec(struct timespec *to, const struct timeval *from)
Definition: porting.c:2173
static void logpb_set_unavailable_archive(THREAD_ENTRY *thread_p, int arv_num)
#define ER_LOG_WRITE
Definition: error_code.h:138
void fileio_make_log_info_name(char *log_info_name_p, const char *log_path_p, const char *db_name_p)
Definition: file_io.c:5815
void logpb_debug_check_log_page(THREAD_ENTRY *thread_p, void *log_pgptr_ptr)
#define ER_TDE_COPY_KEYS_FILE_FAIL
Definition: error_code.h:1616
pthread_cond_t gc_cond
Definition: log_impl.h:320
char db_release[REL_MAX_RELEASE_LENGTH]
logwr_info * writer_info
Definition: log_impl.h:680
int data_header_length
Definition: log_append.hpp:98
bool LSA_GE(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:181
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
void logpb_copy_from_log(THREAD_ENTRY *thread_p, char *area, int length, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
void fileio_abort_restore(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:8980
#define MSGCAT_LOG_LOGINFO_REMOVE_REASON
#define CAST_BUFLEN
Definition: porting.h:471
LOG_PAGEID run_nxchkpt_atpageid
Definition: log_impl.h:655
#define LOG_APPEND_ALIGN(thread_p, current_setdirty)
const char * envvar_get(const char *name)
#define NULL_TRAN_INDEX
LOG_BUFFER * buffers
bool logtb_is_interrupted(THREAD_ENTRY *thread_p, bool clear, bool *continue_checking)
int logpb_remove_archive_logs_exceed_limit(THREAD_ENTRY *thread_p, int max_count)
void logpb_vacuum_reset_log_header_cache(THREAD_ENTRY *thread_p, LOG_HEADER *loghdr)
bool LOG_CS_OWN_WRITE_MODE(THREAD_ENTRY *thread_p)
int logpb_check_and_reset_temp_lsa(THREAD_ENTRY *thread_p, VOLID volid)
static void error(const char *msg)
Definition: gencat.c:331
PGLENGTH db_iopagesize
LOG_LSA prev_lsa
Definition: log_append.hpp:77
#define VACUUM_ER_LOG_VACUUM_DATA
Definition: vacuum.h:52
LOG_PHY_PAGEID nxarv_phy_pageid
void thread_unlock_entry(cubthread::entry *thread_p)
void * fileio_write(THREAD_ENTRY *thread_p, int vol_fd, void *io_page_p, PAGEID page_id, size_t page_size, FILEIO_WRITE_MODE write_mode)
Definition: file_io.c:4150
FILEIO_BACKUP_DB_BUFFER dbfile
Definition: file_io.h:433
#define MSGCAT_LOG_ENTER_Y2_CONFIRM
REL_COMPATIBILITY rel_get_disk_compatible(float db_level, REL_FIXUP_FUNCTION **fixups)
#define LOGPB_FIRST_ACTIVE_PAGE_ID
std::function< void(log_tdes &)> map_func
int logpb_recreate_volume_info(THREAD_ENTRY *thread_p)
STATIC_INLINE void perfmon_inc_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid) __attribute__((ALWAYS_INLINE))
FILEIO_RESTORE_PAGE_BITMAP * fileio_page_bitmap_create(int vol_id, int total_pages)
Definition: file_io.c:11615
#define ER_INTERRUPTED
Definition: error_code.h:51
#define LOG_READ_NEXT_TRANID
Definition: log_impl.h:227
log_global::log_global() char log_Path[PATH_MAX]
Definition: log_global.c:47
int logpb_read_page_from_active_log(THREAD_ENTRY *thread_p, LOG_PAGEID pageid, int num_pages, bool decrypt_needed, LOG_PAGE *log_pgptr)
int log_default_input_for_archive_log_location
#define LOG_ARCHIVE_CS_OWN_WRITE_MODE(thread_p)
Definition: log_impl.h:108
int fileio_get_max_name(const char *given_path_p, long int *file_name_max_p, long int *path_name_max_p)
Definition: file_io.c:5459
#define ER_LOG_NOFULL_DATABASE_NAME_IS_TOO_LONG
Definition: error_code.h:706
int logpb_page_check_corruption(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, bool *is_page_corrupted)
int fileio_request_user_response(THREAD_ENTRY *thread_p, FILEIO_REMOTE_PROMPT_TYPE prompt_id, const char *prompt_p, char *response_p, const char *failure_prompt_p, int range_low, int range_high, const char *secondary_prompt_p, int reprompt_value)
Definition: file_io.c:11304
double total_flush_sec_by_trans
Definition: log_impl.h:718
void tran_cache_tran_settings(int tran_index, int lock_timeout, TRAN_ISOLATION tran_isolation)
#define ER_LOG_BKUP_INCOMPATIBLE
Definition: error_code.h:781
bool restore_upto_bktime
Definition: boot_sr.h:101
#define ARG_FILE_LINE
Definition: error_manager.h:44
void logpb_fatal_error(THREAD_ENTRY *thread_p, bool log_exit, const char *file_name, const int lineno, const char *fmt,...)
static void logpb_dump_pages(FILE *out_fp)
const VOLID LOG_DBTDE_KEYS_VOLID
Definition: log_volids.hpp:41
const char * fileio_get_backup_info_volume_name(FILEIO_BACKUP_LEVEL level, int unit_num, int which_bkvinf)
Definition: file_io.c:11118
#define ER_LOG_CANNOT_ACCESS_BACKUP
Definition: error_code.h:164
LOG_PAGEID vacuum_min_log_pageid_to_keep(THREAD_ENTRY *thread_p)
Definition: vacuum.c:5625
bool is_init
Definition: log_writer.h:169
bool tde_validate_keys_file(int vdes)
Definition: tde.c:358
#define MSGCAT_LOG_MAX_ARCHIVES_HAS_BEEN_EXCEEDED
int fileio_synchronize(THREAD_ENTRY *thread_p, int vol_fd, const char *vlabel, FILEIO_SYNC_OPTION sync_dwb)
Definition: file_io.c:4441
LOG_TOPOPS_STACK topops
Definition: log_impl.h:486
INT16 PGLENGTH
unsigned long direct_flush_count
Definition: log_impl.h:720
int fileio_get_backup_volume(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *user_backuppath, int try_level, char *from_volbackup)
Definition: file_io.c:9846
void disk_unlock_extend(void)
static void logpb_end_append(THREAD_ENTRY *thread_p, LOG_RECORD_HEADER *header)
bool logpb_exist_log(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
LOG_ADDR_TDESAREA * area
Definition: log_impl.h:594
struct arv_page_info ARV_PAGE_INFO
#define ER_LOG_CREATE_LOGARCHIVE_FAIL
Definition: error_code.h:157
LOG_LSA redo_lsa
Definition: log_record.hpp:335
BACKGROUND_ARCHIVING_INFO bg_archive_info
Definition: log_impl.h:682
LOG_PAGEID logpb_find_oldest_available_page_id(THREAD_ENTRY *thread_p)
int logpb_fetch_start_append_page(THREAD_ENTRY *thread_p)
const char * get_db_user() const
FILEIO_BACKUP_RECORD_INFO previnfo[FILEIO_BACKUP_UNDEFINED_LEVEL]
Definition: file_io.h:307
#define LOG_ARCHIVE_CS_ENTER(thread_p)
Definition: log_impl.h:92
bool isloose_end
Definition: log_impl.h:468
static int logpb_add_archive_page_info(THREAD_ENTRY *thread_p, int arv_num, LOG_PAGEID start_page, LOG_PAGEID end_page)
#define free_and_init(ptr)
Definition: memory_alloc.h:147
unsigned long total_sync_count
Definition: log_impl.h:730
#define LOG_ISRESTARTED()
Definition: log_impl.h:232
#define strlen(s1)
Definition: intl_support.c:43
#define LOGPB_NEXT_ARCHIVE_PAGE_ID
VOLID fileio_find_previous_perm_volume(THREAD_ENTRY *thread_p, VOLID volid)
Definition: file_io.c:6434
void LSA_SET_NULL(log_lsa *lsa_ptr)
Definition: log_lsa.hpp:146
#define FILEIO_SECOND_BACKUP_VOL_INFO
Definition: file_io.h:58
int fileio_write_backup_info_entries(FILE *fp, int which_bkvinf)
Definition: file_io.c:11030
int tde_copy_keys_file(THREAD_ENTRY *thread_p, const char *dest_fullname, const char *src_fullname, bool keep_dest_mount, bool keep_src_mount)
Definition: tde.c:398
void fileio_make_dwb_name(char *dwb_name_p, const char *dwb_path_p, const char *db_name_p)
Definition: file_io.c:5881
TRANID trid
Definition: log_impl.h:466
int fileio_backup_volume(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p, const char *from_vol_label_p, VOLID from_vol_id, PAGEID last_page, bool is_only_updated_pages)
Definition: file_io.c:8215
const VOLID LOG_DBLOG_BG_ARCHIVE_VOLID
Definition: log_volids.hpp:51
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
#define MSGCAT_LOG_LOGINFO_COMMENT_FROM_RENAMED
char log_Archive_path[PATH_MAX]
Definition: log_global.c:86
FILEIO_BACKUP_TYPE type
Definition: file_io.h:431
double last_flush_hdr_sec_by_LFT
Definition: log_impl.h:725
#define ER_LOG_ARCHIVE_CREATED
Definition: error_code.h:1215
FILEIO_THREAD_INFO read_thread_info
Definition: file_io.h:434
LOG_LSA smallest_lsa_at_last_chkpt
bool prm_get_bool_value(PARAM_ID prm_id)
bool is_loaded
Definition: tde.h:148
static int logpb_initialize_flush_info(void)
bool trace_last_writer
Definition: log_writer.h:172
char magic[CUBRID_MAGIC_MAX_LENGTH]
#define MSGCAT_LOG_NEWLOCATION
#define ARV_PAGE_INFO_TABLE_SIZE
#define ER_LOG_INCOMPATIBLE_DATABASE
Definition: error_code.h:145
static void logpb_dump_parameter(FILE *outfp)
static void logpb_next_append_page(THREAD_ENTRY *thread_p, LOG_SETDIRTY current_setdirty)
boot_server_status
Definition: boot_sr.h:67
LOG_RECORD_HEADER * record_header_p
static int logpb_get_guess_archive_num(THREAD_ENTRY *thread_p, LOG_PAGEID pageid)
LOG_LSA sysop_start_postpone_lsa
Definition: log_record.hpp:363
void er_clear(void)
unsigned long async_commit_request_count
Definition: log_impl.h:759
bool logpb_is_pool_initialized(void)
#define ALLOC_COPY(PTR, STR)
Definition: cas_common.h:66
FILEIO_BACKUP_SESSION * fileio_initialize_backup(const char *db_full_name_p, const char *backup_destination_p, FILEIO_BACKUP_SESSION *session_p, FILEIO_BACKUP_LEVEL level, const char *verbose_file_path, int num_threads, int sleep_msecs)
Definition: file_io.c:6729
#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
struct log_hdrpage LOG_HDRPAGE
Definition: log_storage.hpp:62
const size_t LOG_USERNAME_MAX
int i
Definition: dynamic_load.c:954
char * msgcat_message(int cat_id, int set_id, int msg_id)
#define ER_LOG_DOESNT_CORRESPOND_TO_DATABASE
Definition: error_code.h:148
void fileio_make_backup_volume_info_name(char *backup_volinfo_name_p, const char *backup_info_path_p, const char *db_name_p)
Definition: file_io.c:5833
void logpb_flush_pages(THREAD_ENTRY *thread_p, LOG_LSA *flush_lsa)
char log_path[PATH_MAX]
Definition: file_io.h:326
void fileio_make_backup_name(char *backup_name_p, const char *no_path_vol_name_p, const char *backup_path_p, FILEIO_BACKUP_LEVEL level, int unit_num)
Definition: file_io.c:5853
#define ER_LOG_UPTODATE_ERROR
Definition: error_code.h:1606
LOG_LSA eof_lsa
VACUUM_LOG_BLOCKID vacuum_last_blockid
void * fileio_write_pages(THREAD_ENTRY *thread_p, int vol_fd, char *io_pages_p, PAGEID page_id, int num_pages, size_t page_size, FILEIO_WRITE_MODE write_mode)
Definition: file_io.c:4314
STATIC_INLINE void perfmon_add_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid, UINT64 amount) __attribute__((ALWAYS_INLINE))
#define ER_LOG_BACKUP_CS_EXIT
Definition: error_code.h:1366
int log_dump_log_info(const char *logname_info, bool also_stdout, const char *fmt,...)
Definition: log_comm.c:205
char magic[CUBRID_MAGIC_MAX_LENGTH]
#define VACUUM_IS_ER_LOG_LEVEL_SET(er_log_level)
Definition: vacuum.h:62
#define NULL_VOLID
#define HA_DISABLED()
TRAN_STATE state
Definition: log_impl.h:469
enum log_cs_access_mode LOG_CS_ACCESS_MODE
Definition: log_impl.h:765
LOG_LSA get_nxio_lsa() const
Definition: log_append.cpp:106
unsigned long total_commit_count_in_flush_pages
Definition: log_impl.h:747
FILEIO_BACKUP_BUFFER bkup
Definition: file_io.h:432
INT16 xdisk_get_purpose_and_sys_lastpage(THREAD_ENTRY *thread_p, INT16 volid, DISK_VOLPURPOSE *vol_purpose, INT32 *sys_lastpage)
#define IO_MAX_PAGE_SIZE
void logpb_dump(THREAD_ENTRY *thread_p, FILE *out_fp)
unsigned long log_buffer_flush_count_by_replacement
Definition: log_impl.h:706
int logpb_copy_page_from_log_buffer(THREAD_ENTRY *thread_p, LOG_PAGEID pageid, LOG_PAGE *log_pgptr)
int fileio_copy_volume(THREAD_ENTRY *thread_p, int from_vol_desc, DKNPAGES npages, const char *to_vol_label_p, VOLID to_vol_id, bool is_reset_recovery_info)
Definition: file_io.c:2809
#define LOG_PAGESIZE
static int logpb_fetch_header_from_active_log(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname, LOG_HEADER *hdr, LOG_PAGE *log_pgptr)
unsigned long flushall_append_pages_call_count
Definition: log_impl.h:710
int dwb_destroy(THREAD_ENTRY *thread_p)
VACUUM_LOG_BLOCKID logpb_last_complete_blockid(void)
#define ER_LOG_INCOMPATIBLE_PREFIX_NAME
Definition: error_code.h:144
#define ER_TDE_INVALID_KEYS_FILE
Definition: error_code.h:1608
void logtb_undefine_trantable(THREAD_ENTRY *thread_p)
static int rv
INT32 PAGEID
void logtb_find_smallest_lsa(THREAD_ENTRY *thread_p, LOG_LSA *lsa)
void disk_lock_extend(void)
size_t logpb_get_memsize()
LOG_LSA bkup_level0_lsa
TRANID next_trid
#define ER_TM_CROSS_DEVICE_LINK
Definition: error_code.h:1101
MVCCID mvcc_next_id
static int logpb_backup_for_volume(THREAD_ENTRY *thread_p, VOLID volid, LOG_LSA *chkpt_lsa, FILEIO_BACKUP_SESSION *session, bool only_updated)
#define pthread_mutex_unlock(a)
int logpb_write_page_to_disk(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, LOG_PAGEID logical_pageid)
#define ER_LOG_CHECKPOINT_STARTED
Definition: error_code.h:1221
const char * rel_release_string(void)
LOG_PAGE ** toflush
Definition: log_impl.h:307
int logpb_copy_database(THREAD_ENTRY *thread_p, VOLID num_perm_vols, const char *to_db_fullname, const char *to_logpath, const char *to_prefix_logname, const char *toext_path, const char *fileof_vols_and_copypaths)
LOG_LSA tran_start_postpone_lsa
Definition: log_impl.h:450
#define TR_TABLE_CS_EXIT(thread_p)
Definition: log_impl.h:90
#define PEEK
Definition: file_io.h:74
int timeval_add_msec(struct timeval *added_time, const struct timeval *start_time, int msec)
Definition: porting.c:2152
int tde_decrypt_log_page(const LOG_PAGE *logpage_cipher, TDE_ALGORITHM tde_algo, LOG_PAGE *logpage_plain)
Definition: tde.c:1027
LOG_LSA mvcc_op_log_lsa
double gc_total_wait_time
Definition: log_impl.h:753
void logpb_initialize_logging_statistics(void)
FILEIO_BACKUP_LEVEL
Definition: file_io.h:96
LOG_PHY_PAGEID logpb_to_physical_pageid(LOG_PAGEID logical_pageid)
int logpb_checkpoint_topops(THREAD_ENTRY *thread_p, LOG_INFO_CHKPT_SYSOP *&chkpt_topops, LOG_INFO_CHKPT_TRANS *chkpt_trans, LOG_REC_CHKPT &tmp_chkpt, log_tdes *tdes, int &ntops, size_t &length_all_tops)
bool printtoc
Definition: boot_sr.h:94
void logpb_create_log_info(const char *logname_info, const char *db_fullname)
int pgbuf_flush_checkpoint(THREAD_ENTRY *thread_p, const LOG_LSA *flush_upto_lsa, const LOG_LSA *prev_chkpt_redo_lsa, LOG_LSA *smallest_lsa, int *flushed_page_cnt)
Definition: page_buffer.c:3552
#define LOGPB_IS_FIRST_PHYSICAL_PAGE(pageid)
FILEIO_ZIP_METHOD
Definition: file_io.h:104
#define pthread_mutex_init(a, b)
int fileio_open(const char *vol_label_p, int flags, int mode)
Definition: file_io.c:1957
LOGPB_APPENDREC_STATUS status
LOG_LSA atomic_sysop_start_lsa
Definition: log_impl.h:454
const size_t LOGPB_IO_NPAGES
Definition: log_storage.hpp:55
void fileio_make_volume_info_name(char *vol_info_name_p, const char *db_full_name_p)
Definition: file_io.c:5636
#define pthread_mutex_destroy(a)
static void map_all_tdes(const map_func &func)
LOG_LSA chkpt_lsa
std::int64_t offset
Definition: log_lsa.hpp:37
#define MSGCAT_LOG_STARTS
LOG_LOGGING_STAT log_Stat
#define DB_CONNECTION_STATUS_NOT_CONNECTED
Definition: db.h:46
const char ** p
Definition: dynamic_load.c:945
bool newvolpath
Definition: boot_sr.h:99
#define ER_LOG_COMPILATION_RELEASE
Definition: error_code.h:147
void logpb_initialize_arv_page_info_table(void)
#define ER_LOG_CREATE_DBBACKUP_DIRINFO
Definition: error_code.h:158
#define LOG_APPEND_ADVANCE_WHEN_DOESNOT_FIT(thread_p, length)
int db_set_page_size(PGLENGTH io_page_size, PGLENGTH log_page_size)
int logpb_scan_volume_info(THREAD_ENTRY *thread_p, const char *db_fullname, VOLID ignore_volid, VOLID start_volid, int(*fun)(THREAD_ENTRY *thread_p, VOLID xvolid, const char *vlabel, void *args), void *args)
static void logpb_finalize_writer_info(void)
void pgbuf_reset_temp_lsa(PAGE_PTR pgptr)
Definition: page_buffer.c:4457
LOG_RECORD_HEADER original_record_header
const TRANID LOG_SYSTEM_TRANID
unsigned long total_commit_count_while_using_a_page
Definition: log_impl.h:742
char buffer_log_page[IO_MAX_PAGE_SIZE+MAX_ALIGNMENT]
const log_lsa NULL_LSA
Definition: log_lsa.hpp:59
void logpb_fatal_error_exit_immediately_wo_flush(THREAD_ENTRY *thread_p, const char *file_name, const int lineno, const char *fmt,...)
static bool logpb_remote_ask_user_before_delete_volumes(THREAD_ENTRY *thread_p, const char *volpath)
static LOG_PAGE ** logpb_writev_append_pages(THREAD_ENTRY *thread_p, LOG_PAGE **to_flush, DKNPAGES npages)
#define LOG_READ_ADVANCE_WHEN_DOESNT_FIT(thread_p, length, lsa, log_pgptr)
Definition: log_impl.h:149
#define LOG_LAST_APPEND_PTR()
int perm_status_obsolete
bool does_block_need_vacuum
int fileio_get_volume_descriptor(VOLID vol_id)
Definition: file_io.c:6488
int tde_encrypt_log_page(const LOG_PAGE *logpage_plain, TDE_ALGORITHM tde_algo, LOG_PAGE *logpage_cipher)
Definition: tde.c:997
#define log_archive_er_log(...)
#define ER_BO_CANNOT_FINE_VOLINFO
Definition: error_code.h:650
#define logpb_log(...)
#define MSGCAT_LOG_LOGARCHIVE_NEEDED
LOGWR_ENTRY * next
Definition: log_writer.h:153
static void logpb_append_crumbs(THREAD_ENTRY *thread_p, int num_crumbs, const LOG_CRUMB *crumbs)
static int logpb_copy_log_header(THREAD_ENTRY *thread_p, LOG_HEADER *to_hdr, const LOG_HEADER *from_hdr)
char db_fullname[PATH_MAX]
Definition: file_io.h:296