CUBRID Engine  latest
file_io.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  * file_io.c - input/output module (at server)
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdlib.h>
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <time.h>
34 #include <limits.h>
35 #include <sys/stat.h>
36 #include <assert.h>
37 #include <signal.h>
38 
39 #if defined(WINDOWS)
40 #include <io.h>
41 #include <share.h>
42 #else /* WINDOWS */
43 #include <unistd.h>
44 #include <sys/time.h>
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/uio.h>
48 #include <sys/vfs.h>
49 #if defined (SERVER_MODE)
50 #include <syslog.h>
51 #endif
52 #endif /* WINDOWS */
53 
54 #ifdef _AIX
55 #include <sys/statfs.h>
56 #endif /* _AIX */
57 
58 #if defined(SOLARIS)
59 #include <sys/statvfs.h>
60 #include <netdb.h>
61 #endif /* SOLARIS */
62 
63 #if defined(HPUX)
64 #include <sys/scsi.h>
65 #include <aio.h>
66 #endif /* HPUX */
67 
68 #include "porting.h"
69 
70 #include "chartype.h"
71 #include "connection_globals.h"
72 #include "file_io.h"
73 #include "storage_common.h"
74 #include "memory_alloc.h"
75 #include "error_manager.h"
76 #include "system_parameter.h"
77 #include "message_catalog.h"
78 #include "msgcat_set_log.hpp"
79 #include "object_representation.h"
80 #include "util_func.h"
81 #include "perf_monitor.h"
82 #include "environment_variable.h"
83 #include "connection_error.h"
84 #include "release_string.h"
85 #include "log_common_impl.h"
86 #include "log_volids.hpp"
87 #include "fault_injection.h"
88 #if defined (SERVER_MODE)
89 #include "vacuum.h"
90 #endif /* SERVER_MODE */
91 #include "crypt_opfunc.h"
92 
93 #if defined(WINDOWS)
94 #include "wintcp.h"
95 #else /* WINDOWS */
96 #include "tcp.h"
97 #endif /* WINDOWS */
98 
99 #if defined(SERVER_MODE)
100 #include "connection_error.h"
101 #include "network_interface_sr.h"
102 #endif /* SERVER_MODE */
103 
104 #if !defined (CS_MODE)
105 #include "double_write_buffer.h"
106 #include "page_buffer.h"
107 #include "xserver_interface.h"
108 #endif /* !defined (CS_MODE) */
109 
110 #include "intl_support.h"
111 #include "tsc_timer.h"
112 
113 #if defined (SERVER_MODE)
114 #include "server_support.h"
115 #endif // SERVER_MODE
116 #if defined (SERVER_MODE)
117 #include "thread_entry_task.hpp"
118 #endif // SERVER_MODE
119 #if defined (SERVER_MODE)
120 #include "thread_manager.hpp" // for thread_get_thread_entry_info and thread_sleep
121 #endif // SERVER_MODE
122 
123 /************************************************************************/
124 /* TODO: why is this in client module? */
125 /************************************************************************/
126 
127 /*
128  * Message id in the set MSGCAT_SET_IO
129  * in the message catalog MSGCAT_CATALOG_CUBRID (file cubrid.msg).
130  */
131 #define MSGCAT_FILEIO_STARTS 1
132 #define MSGCAT_FILEIO_BKUP_NEEDED 2
133 #define MSGCAT_FILEIO_BKUP_HDR 3
134 #define MSGCAT_FILEIO_BKUP_HDR_MAGICID 4
135 #define MSGCAT_FILEIO_BKUP_HDR_RELEASES 5
136 #define MSGCAT_FILEIO_BKUP_HDR_DBINFO 6
137 #define MSGCAT_FILEIO_BKUP_HDR_LEVEL 7
138 #define MSGCAT_FILEIO_BKUP_HDR_TIME 8
139 #define MSGCAT_FILEIO_BKUP_FILE 9
140 #define MSGCAT_FILEIO_REST_RELO_NEEDED 10
141 #define MSGCAT_FILEIO_REST_RELO_OPTIONS 11
142 #define MSGCAT_FILEIO_NEWLOCATION 12
143 #define MSGCAT_FILEIO_INPUT_RANGE_ERROR 13
144 #define MSGCAT_FILEIO_INCORRECT_BKVOLUME 14
145 #define MSGCAT_FILEIO_LEVEL_MISMATCH 15
146 #define MSGCAT_FILEIO_MAGIC_MISMATCH 16
147 #define MSGCAT_FILEIO_DB_MISMATCH 17
148 #define MSGCAT_FILEIO_UNIT_NUM_MISMATCH 18
149 #define MSGCAT_FILEIO_BACKUP_TIME_MISMATCH 19
150 #define MSGCAT_FILEIO_BACKUP_VINF_ERROR 20
151 #define MSGCAT_FILEIO_BACKUP_LABEL_INFO 21
152 #define MSGCAT_FILEIO_BKUP_HDR_LX_LSA 22
153 #define MSGCAT_FILEIO_RESTORE_FIND_REASON 23
154 #define MSGCAT_FILEIO_BKUP_FIND_REASON 24
155 #define MSGCAT_FILEIO_BKUP_PREV_BKVOL 25
156 #define MSGCAT_FILEIO_BKUP_NEXT_BKVOL 26
157 #define MSGCAT_FILEIO_BKUP_HDR_BKUP_PAGESIZE 27
158 #define MSGCAT_FILEIO_BKUP_HDR_ZIP_INFO 28
159 #define MSGCAT_FILEIO_BKUP_HDR_INC_ACTIVELOG 29
160 
161 #ifdef L_cuserid
162 #define FILEIO_USER_NAME_SIZE L_cuserid
163 #else /* L_cuserid */
164 #define FILEIO_USER_NAME_SIZE 9
165 #endif /* L_cuserid */
166 
167 #if defined(WINDOWS)
168 #define GETPID() GetCurrentProcessId()
169 #else /* WINDOWS */
170 #define GETPID() getpid()
171 #endif /* WINDOWS */
172 
173 #define FILEIO_DISK_FORMAT_MODE (O_RDWR | O_CREAT)
174 #define FILEIO_DISK_PROTECTION_MODE 0600
175 #define FILEIO_MAX_WAIT_DBTXT 300
176 #define FILEIO_FULL_LEVEL_EXP 32
177 
178 /*
179  * Define a fixed size for backup and restore input/output of the volume
180  * headers. For most modern devices multiples of 512 or 1024 are needed.
181  * A size of the header data is computed in compile.
182  */
183 #define GET_NEXT_1K_SIZE(s) (((((s) - 1) / 1024) + 1) * 1024)
184 #define FILEIO_BACKUP_HEADER_IO_SIZE GET_NEXT_1K_SIZE(sizeof(FILEIO_BACKUP_HEADER))
185 #define FILEIO_GET_FILE_SIZE(pagesize, npages) \
186  (((off_t)(pagesize)) * ((off_t)(npages)))
187 
188 #define FILEIO_BACKUP_NO_ZIP_HEADER_VERSION 1
189 #define FILEIO_BACKUP_CURRENT_HEADER_VERSION 2
190 #define FILEIO_CHECK_FOR_INTERRUPT_INTERVAL 100
191 
192 #define FILEIO_PAGE_SIZE_FULL_LEVEL (IO_PAGESIZE * FILEIO_FULL_LEVEL_EXP)
193 #define FILEIO_BACKUP_PAGE_OVERHEAD \
194  (offsetof(FILEIO_BACKUP_PAGE, iopage) + sizeof(PAGEID))
195 #define FILEIO_BACKUP_DBVOLS_IO_PAGE_SIZE \
196  (IO_PAGESIZE + FILEIO_BACKUP_PAGE_OVERHEAD)
197 #define FILEIO_BACKUP_DBVOLS_IO_PAGE_SIZE_FULL_LEVEL \
198  (FILEIO_PAGE_SIZE_FULL_LEVEL + FILEIO_BACKUP_PAGE_OVERHEAD)
199 
200 #define FILEIO_RESTORE_DBVOLS_IO_PAGE_SIZE(sess) \
201  ((sess)->bkup.bkuphdr->bkpagesize + FILEIO_BACKUP_PAGE_OVERHEAD)
202 
203 #define FILEIO_DBVOLS_IO_PAGE_SIZE(backup_header_p) \
204  ((backup_header_p)->bkpagesize + FILEIO_BACKUP_PAGE_OVERHEAD)
205 
206 #define FILEIO_BACKUP_FILE_HEADER_PAGE_SIZE \
207  (sizeof(FILEIO_BACKUP_FILE_HEADER) + offsetof(FILEIO_BACKUP_PAGE, iopage))
208 
209 /* Set just the redundant copy of the pageid to the given page. */
210 #define FILEIO_SET_BACKUP_PAGE_ID_COPY(area, pageid, psize) \
211  *(PAGEID *)(((char *)(area)) + \
212  (offsetof(FILEIO_BACKUP_PAGE, iopage) + psize)) = pageid
213 
214 /* Set the backup page pageid(s) */
215 #define FILEIO_SET_BACKUP_PAGE_ID(area, pageid, psize) \
216  do { \
217  ((FILEIO_BACKUP_PAGE *)(area))->iopageid = pageid; \
218  /* set the redundant copy of the pageid, alignment is important */ \
219  FILEIO_SET_BACKUP_PAGE_ID_COPY(area, pageid, psize); \
220  } while (false);
221 
222 /* Get the backup page primary pageid */
223 #define FILEIO_GET_BACKUP_PAGE_ID(area) (((FILEIO_BACKUP_PAGE *)(area))->iopageid)
224 
225 /*
226  * Verify the integrity of the page just read by checking the redundant
227  * copy of the pageid. Remember that the ->iopageid_copy cannot be accessed
228  * directly and must be retrieved by pointer offset. If the two pageid's
229  * do not match it is probably a corrupted page.
230  */
231 #define FILEIO_CHECK_RESTORE_PAGE_ID(area, pagesz) \
232  (((FILEIO_BACKUP_PAGE *)(area))->iopageid == \
233  *(PAGEID *)(((char *)(area)) + offsetof(FILEIO_BACKUP_PAGE, iopage) + pagesz))
234 
235 /* Define minimum number of pages required for a backup volume
236  For now, specify at least 4 pages plus the header. */
237 #define FILEIO_BACKUP_MINIMUM_NUM_PAGES \
238  CEIL_PTVDIV((FILEIO_BACKUP_HEADER_IO_SIZE + \
239  (FILEIO_BACKUP_DBVOLS_IO_PAGE_SIZE) * 4), IO_PAGESIZE)
240 #define FILEIO_BACKUP_MINIMUM_NUM_PAGES_FULL_LEVEL \
241  CEIL_PTVDIV((FILEIO_BACKUP_HEADER_IO_SIZE + \
242  (FILEIO_BACKUP_DBVOLS_IO_PAGE_SIZE_FULL_LEVEL) * 4), IO_PAGESIZE)
243 
244 #define FILEIO_CHECK_AND_INITIALIZE_VOLUME_HEADER_CACHE(rtn) \
245  do { \
246  if (fileio_Vol_info_header.volinfo == NULL \
247  && fileio_initialize_volume_info_cache () < 0) \
248  return (rtn); \
249  } while (0)
250 
251 /* Some specifications of page identifiers of backup */
252 #define FILEIO_BACKUP_START_PAGE_ID (-2)
253 #define FILEIO_BACKUP_END_PAGE_ID (-3)
254 #define FILEIO_BACKUP_FILE_START_PAGE_ID (-4)
255 #define FILEIO_BACKUP_FILE_END_PAGE_ID (-5)
256 #define FILEIO_BACKUP_VOL_CONT_PAGE_ID (-6)
257 
258 #define FILEIO_END_OF_FILE (1)
259 
260 /* Minimum flush rate 40MB/s */
261 #define FILEIO_MIN_FLUSH_PAGES_PER_SEC (41943040 / IO_PAGESIZE)
262 /* TODO: Growth/drop flush rate values can be tweaked. They have been set to
263  * meet the needs of stressful workload. They have been set to drop slowly and
264  * grow back quickly.
265  * Please consider that token consumption depend on two factors:
266  * 1. System IO capabilities.
267  * 2. Flush thinking time.
268  * If flush thinking time prevents it from consuming tokens, we might reduce
269  * the numbers of token for next iterations unwillingly. A fast drop rate and
270  * slow growth rate can make it impossible to recover from a "missed"
271  * iteration (e.g. flush has been blocked on AIN list mutex).
272  */
273 /* Rate of growing flush rate when tokens are consumed. */
274 #define FILEIO_PAGE_FLUSH_GROW_RATE 0.5
275 /* Rate of reducing flush rate when tokens are not consumed. */
276 #define FILEIO_PAGE_FLUSH_DROP_RATE 0.1
277 
278 #if defined(WINDOWS)
279 #define fileio_lock_file_write(fd, offset, whence, len) \
280  fileio_lock_region(fd, F_TLOCK, offset, len)
281 #define fileio_lock_file_writew(fd, offset, whence, len) \
282  fileio_lock_region(fd, F_LOCK, offset, len)
283 #define fileio_lock_file_read(fd, offset, whence, len) \
284  fileio_lock_region(fd, F_TLOCK, offset, len)
285 #define fileio_lock_file_readw(fd, offset, whence, len) \
286  fileio_lock_region(fd, F_LOCK, offset, len)
287 #define fileio_unlock_file(fd, offset, whence, len) \
288  fileio_lock_region(fd, F_ULOCK, offset, len)
289 #else /* WINDOWS */
290 #define fileio_lock_file_read(fd, offset, whence, len) \
291  fileio_lock_region(fd, F_SETLK, F_RDLCK, offset, whence, len)
292 #define fileio_lock_file_readw(fd, offset, whence, len) \
293  fileio_lock_region(fd, F_SETLKW, F_RDLCK, offset, whence, len)
294 #define fileio_lock_file_write(fd, offset, whence, len) \
295  fileio_lock_region(fd, F_SETLK, F_WRLCK, offset, whence, len)
296 #define fileio_lock_file_writew(fd, offset, whence, len) \
297  fileio_lock_region(fd, F_SETLKW, F_WRLCK, offset, whence, len)
298 #define fileio_unlock_file(fd, offset, whence, len) \
299  fileio_lock_region(fd, F_SETLK, F_UNLCK, offset, whence, len)
300 #endif /* WINDOWS */
301 
302 #define FILEIO_VOLINFO_INCREMENT 32
303 
304 #if !defined(SERVER_MODE)
305 #define pthread_mutex_init(a, b)
306 #define pthread_mutex_destroy(a)
307 #define pthread_mutex_lock(a) 0
308 #define pthread_mutex_unlock(a)
309 static int rv;
310 #endif
311 
312 /* User input states when requesting relocation of a (backup) volume. */
313 typedef enum
314 {
321 
329 
330 /* A FILE/VOLUME HEADER IN BACKUP */
332 {
333  INT64 nbytes;
335  short dummy1; /* Dummy field for 8byte align */
336  int dummy2; /* Dummy field for 8byte align */
337  char vlabel[PATH_MAX];
338 };
339 
340 /* Some specifications for bkvinf data */
341 
342 /* Each one of these represents a given backup volume unit */
344 {
345  int unit_num;
346  char bkvol_name[PATH_MAX];
348 };
349 
350 /* Master data structure to retain information about each backup level */
352 {
356 };
357 
358 /* Volume information structure for system volumes(volid < NULL_VOLID) */
360 {
362  int vdes;
364  char vlabel[PATH_MAX];
365 #if defined(SERVER_MODE) && defined(WINDOWS)
366  pthread_mutex_t sysvol_mutex;
367 #endif /* SERVER_MODE && WINDOWS */
369 };
370 
371 /* System volume informations are linked as a list */
373 {
374 #if defined(SERVER_MODE)
375  pthread_mutex_t mutex;
376 #endif /* SERVER_MODE */
377  int num_vols;
379 };
380 
381 /* Volume information structure for perm/temp volumes */
383 {
385  int vdes;
387 #if defined(SERVER_MODE) && defined(WINDOWS)
388  pthread_mutex_t vol_mutex; /* for fileio_read()/fileio_write() */
389 #endif /* SERVER_MODE && WINDOWS */
390  char vlabel[PATH_MAX];
391 };
392 
394 {
395  int vol_id;
396  int vdes;
397  const char *vol_label;
398 } APPLY_ARG;
399 
400 /* Perm/temp volume informations are stored on array.
401  * Direct access by volid is possible */
403 {
404 #if defined(SERVER_MODE)
405  pthread_mutex_t mutex;
406 #endif /* SERVER_MODE */
407  int max_perm_vols; /* # of max. io_volinfo entries for perm. vol */
408  int next_perm_volid; /* # of used io_volinfo entries for perm. vol */
409  int max_temp_vols; /* # of max. io_volinfo entries for temp. vol */
410  int next_temp_volid; /* # of used io_volinfo entries for temp. vol */
411  /* if volid of volume is equal to this value, */
412  /* it is temp. volume */
413  int num_volinfo_array; /* # of io_volinfo entry chunks */
414  FILEIO_VOLUME_INFO **volinfo; /* array of pointer for io_volinfo chunks */
415 };
416 
417 typedef bool (*VOLINFO_APPLY_FN) (THREAD_ENTRY * thread_p, FILEIO_VOLUME_INFO * vol_info_p, APPLY_ARG * arg);
418 typedef bool (*SYS_VOLINFO_APPLY_FN) (THREAD_ENTRY * thread_p, FILEIO_SYSTEM_VOLUME_INFO * sys_vol_info_p,
419  APPLY_ARG * arg);
420 
422 #if defined(SERVER_MODE)
423  PTHREAD_MUTEX_INITIALIZER,
424 #endif /* SERVER_MODE */
425  0,
426  {
428 #if defined(SERVER_MODE) && defined(WINDOWS)
429  PTHREAD_MUTEX_INITIALIZER,
430 #endif /* SERVER_MODE && WINDOWS */
431  NULL}
432 };
433 
435 #if defined(SERVER_MODE)
436  PTHREAD_MUTEX_INITIALIZER,
437 #endif /* SERVER_MODE */
438  0, 0, 0, LOG_MAX_DBVOLID, 0, NULL
439 };
440 
441 /* Records information from the bkvinf file about backup volumes */
443  { {false, {NULL, NULL, NULL}, NULL}, {false, {NULL, NULL, NULL}, NULL} };
444 
445 /* Flush Control */
446 #if !defined(HAVE_ATOMIC_BUILTINS)
447 static pthread_mutex_t fileio_Flushed_page_counter_mutex = PTHREAD_MUTEX_INITIALIZER;
448 #endif
450 
454 
455 #if defined(CUBRID_DEBUG)
456 /* Set this to get various levels of io information regarding
457  * backup and restore activity.
458  * 0 :: no output
459  * 1 :: print names and sizes of volumes that are backed-up.
460  * 2 :: dump page bitmaps after volume is restored.
461  */
462 static int io_Bkuptrace_debug = -1;
463 #endif /* CUBRID_DEBUG */
464 
465 #if defined(SERVER_MODE) && defined(WINDOWS)
466 static pthread_mutex_t *fileio_get_volume_mutex (THREAD_ENTRY * thread_p, int vdes);
467 #endif
468 static int fileio_initialize_volume_info_cache (void);
469 static void fileio_make_volume_lock_name (char *vol_lockname, const char *vol_fullname);
470 static int fileio_create (THREAD_ENTRY * thread_p, const char *db_fullname, const char *vlabel, VOLID volid,
471  bool dolock, bool dosync);
472 static int fileio_create_backup_volume (THREAD_ENTRY * thread_p, const char *db_fullname, const char *vlabel,
473  VOLID volid, bool dolock, bool dosync, int atleast_pages);
474 static int fileio_max_permanent_volumes (int index, int num_permanent_volums);
475 static int fileio_min_temporary_volumes (int index, int num_temp_volums, int num_volinfo_array);
477  SYS_VOLINFO_APPLY_FN apply_function, APPLY_ARG * arg);
479  APPLY_ARG * arg);
481  VOLINFO_APPLY_FN apply_function, APPLY_ARG * arg);
483  APPLY_ARG * arg);
485  VOLINFO_APPLY_FN apply_function, APPLY_ARG * arg);
486 
487 static bool fileio_dismount_volume (THREAD_ENTRY * thread_p, FILEIO_VOLUME_INFO * vol_info_p, APPLY_ARG * ignore_arg);
488 static bool fileio_is_volume_descriptor_equal (THREAD_ENTRY * thread_p, FILEIO_VOLUME_INFO * vol_info_p,
489  APPLY_ARG * arg);
490 static bool fileio_is_volume_id_gt (THREAD_ENTRY * thread_p, FILEIO_VOLUME_INFO * vol_info_p, APPLY_ARG * arg);
491 static bool fileio_is_volume_id_lt (THREAD_ENTRY * thread_p, FILEIO_VOLUME_INFO * vol_info_p, APPLY_ARG * arg);
493  SYS_VOLINFO_APPLY_FN apply_function, APPLY_ARG * arg);
495  FILEIO_SYSTEM_VOLUME_INFO * sys_vol_info_p, APPLY_ARG * arg);
496 static bool fileio_is_system_volume_id_equal (THREAD_ENTRY * thread_p, FILEIO_SYSTEM_VOLUME_INFO * sys_vol_info_p,
497  APPLY_ARG * arg);
498 static bool fileio_is_system_volume_label_equal (THREAD_ENTRY * thread_p, FILEIO_SYSTEM_VOLUME_INFO * sys_vol_info_p,
499  APPLY_ARG * arg);
500 static bool fileio_synchronize_sys_volume (THREAD_ENTRY * thread_p, FILEIO_SYSTEM_VOLUME_INFO * vol_sys_info_p,
501  APPLY_ARG * arg);
502 static bool fileio_synchronize_volume (THREAD_ENTRY * thread_p, FILEIO_VOLUME_INFO * vol_info_p, APPLY_ARG * arg);
503 static int fileio_cache (VOLID volid, const char *vlabel, int vdes, FILEIO_LOCKF_TYPE lockf_type);
504 static void fileio_decache (THREAD_ENTRY * thread_p, int vdes);
505 static VOLID fileio_get_volume_id (int vdes);
506 static bool fileio_is_volume_label_equal (THREAD_ENTRY * thread_p, FILEIO_VOLUME_INFO * vol_info_p, APPLY_ARG * arg);
509 static bool fileio_is_terminated_process (int pid);
510 
511 static ssize_t fileio_os_read (THREAD_ENTRY * thread_p, int vol_fd, void *io_page_p, size_t count, off_t offset);
512 static ssize_t fileio_os_write (THREAD_ENTRY * thread_p, int vol_fd, void *io_page_p, size_t count, off_t offset);
513 #if !defined (WINDOWS)
514 static ssize_t pwrite_with_injected_fault (THREAD_ENTRY * thread_p, int fd, const void *buf, size_t count,
515  off_t offset);
516 #endif
517 
518 #if !defined(WINDOWS)
519 static FILEIO_LOCKF_TYPE fileio_lock (const char *db_fullname, const char *vlabel, int vdes, bool dowait);
520 static void fileio_unlock (const char *vlabel, int vdes, FILEIO_LOCKF_TYPE lockf_type);
521 static FILEIO_LOCKF_TYPE fileio_get_lockf_type (int vdes);
522 #endif /* !WINDOWS */
523 
524 static int fileio_get_primitive_way_max (const char *path, long int *filename_max, long int *pathname_max);
525 static int fileio_flush_backup (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session);
526 static ssize_t fileio_read_backup (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session, int pageid);
527 static int fileio_write_backup (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session, ssize_t towrite_nbytes);
529 
530 static FILEIO_BACKUP_SESSION *fileio_initialize_restore (THREAD_ENTRY * thread_p, const char *db_fullname,
531  char *backup_src, FILEIO_BACKUP_SESSION * session,
532  FILEIO_BACKUP_LEVEL level,
533  const char *restore_verbose_file_path, bool newvolpath);
534 static int fileio_read_restore (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session, int toread_nbytes);
535 static void *fileio_write_restore (THREAD_ENTRY * thread_p, FILEIO_RESTORE_PAGE_BITMAP * page_bitmap, int vdes,
536  void *io_pgptr, VOLID vol_id, PAGEID page_id, FILEIO_BACKUP_LEVEL level);
539  char *to_volname, int unit_num, FILEIO_BACKUP_LEVEL level,
540  int reason);
541 
542 static int fileio_get_next_backup_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session, bool user_new);
543 static int fileio_initialize_backup_info (int which_bkvinf);
544 static FILEIO_BACKUP_INFO_ENTRY *fileio_allocate_backup_info (int which_bkvinf);
545 
546 static FILEIO_BACKUP_SESSION *fileio_continue_restore (THREAD_ENTRY * thread_p, const char *db_fullname,
547  INT64 db_creation, FILEIO_BACKUP_SESSION * session,
548  bool first_time, bool authenticate, INT64 match_bkupcreation);
549 static int fileio_fill_hole_during_restore (THREAD_ENTRY * thread_p, int *next_pageid, int stop_pageid,
551 static int fileio_decompress_restore_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session, int nbytes);
555 static int fileio_compress_backup_node (FILEIO_NODE * node, FILEIO_BACKUP_HEADER * backup_hdr);
556 static int fileio_write_backup_node (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session, FILEIO_NODE * node,
557  FILEIO_BACKUP_HEADER * backup_hdr);
558 static char *fileio_ctime (INT64 * clock, char *buf);
559 static const char *fileio_get_backup_level_string (FILEIO_BACKUP_LEVEL level);
560 
561 static int fileio_initialize_backup_thread (FILEIO_BACKUP_SESSION * session_p, int num_threads);
562 static void fileio_finalize_backup_thread (FILEIO_BACKUP_SESSION * session_p, FILEIO_ZIP_METHOD zip_method);
563 static int fileio_write_backup_end_time_to_header (FILEIO_BACKUP_SESSION * session_p, INT64 end_time);
564 static void fileio_write_backup_end_time_to_last_page (FILEIO_BACKUP_SESSION * session_p, INT64 end_time);
566 
567 #if !defined(WINDOWS)
568 static int fileio_get_lock (int fd, const char *vlabel);
569 static int fileio_release_lock (int fd);
570 static int fileio_lock_region (int fd, int cmd, int type, off_t offset, int whence, off_t len);
571 #endif /* !WINDOWS */
572 
573 #if defined(SERVER_MODE)
574 static void fileio_read_backup_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session);
575 static FILEIO_TYPE fileio_write_backup_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session);
576 static FILEIO_NODE *fileio_append_queue (FILEIO_QUEUE * qp, FILEIO_NODE * node);
577 #endif /* SERVER_MODE */
578 
579 static void fileio_compensate_flush (THREAD_ENTRY * thread_p, int fd, int npage);
580 static int fileio_increase_flushed_page_count (int npages);
581 static int fileio_flush_control_get_token (THREAD_ENTRY * thread_p, int ntoken);
583 static int fileio_synchronize_bg_archive_volume (THREAD_ENTRY * thread_p);
584 
587 static void fileio_page_bitmap_dump (FILE * out_fp, const FILEIO_RESTORE_PAGE_BITMAP * page_bitmap);
588 
589 static int
591 {
592  int flushed_page_count;
593 
594 #if defined(HAVE_ATOMIC_BUILTINS)
595  flushed_page_count = ATOMIC_INC_32 (&fileio_Flushed_page_count, npages);
596 #else
598  fileio_Flushed_page_count += npages;
599  flushed_page_count = fileio_Flushed_page_count;
601 #endif /* HAVE_ATOMIC_BUILTINS */
602 
603  return flushed_page_count;
604 }
605 
606 static void
607 fileio_compensate_flush (THREAD_ENTRY * thread_p, int fd, int npage)
608 {
609 #if !defined(SERVER_MODE)
610  return;
611 #else
612  int rv;
613  bool need_sync;
614  int flushed_page_count;
615 
616  assert (npage > 0);
617 
618  if (npage <= 0)
619  {
620  return;
621  }
622 
623  if (thread_p == NULL)
624  {
625  thread_p = thread_get_thread_entry_info ();
626  }
627 
628  rv = fileio_flush_control_get_token (thread_p, npage);
629  if (rv != NO_ERROR)
630  {
631  return;
632  }
633 
634  need_sync = false;
635 
636  flushed_page_count = fileio_increase_flushed_page_count (npage);
637  if (flushed_page_count > prm_get_integer_value (PRM_ID_PB_SYNC_ON_NFLUSH))
638  {
639  need_sync = true;
641  }
642 
643  if (need_sync)
644  {
645  fileio_synchronize_all (thread_p, false);
646  }
647 #endif /* SERVER_MODE */
648 }
649 
650 /*
651  * fileio_flush_control_initialize():
652  *
653  * returns:
654  *
655  * Note:
656  */
657 int
659 {
660 #if !defined(SERVER_MODE)
661  return NO_ERROR;
662 #else
663  TOKEN_BUCKET *tb;
664  int rv = NO_ERROR;
665 
666  assert (fc_Token_bucket == NULL);
667  tb = &fc_Token_bucket_s;
668 
669  rv = pthread_mutex_init (&tb->token_mutex, NULL);
670  if (rv != NO_ERROR)
671  {
674  }
675  tb->tokens = 0;
676  tb->token_consumed = 0;
677 
678  rv = pthread_cond_init (&tb->waiter_cond, NULL);
679  if (rv != 0)
680  {
683  }
684 
685  fc_Stats.num_tokens = 0;
686  fc_Stats.num_log_pages = 0;
687  fc_Stats.num_pages = 0;
688 
689  fc_Token_bucket = tb;
690  return rv;
691 #endif
692 }
693 
694 /*
695  * fileio_flush_control_finalize():
696  *
697  * returns:
698  *
699  * Note:
700  */
701 void
703 {
704 #if !defined(SERVER_MODE)
705  return;
706 #else
707  TOKEN_BUCKET *tb;
708 
709  assert (fc_Token_bucket != NULL);
710  if (fc_Token_bucket == NULL)
711  {
712  return;
713  }
714 
715  tb = fc_Token_bucket;
716  fc_Token_bucket = NULL;
717 
718  (void) pthread_mutex_destroy (&tb->token_mutex);
719  (void) pthread_cond_destroy (&tb->waiter_cond);
720 #endif
721 }
722 
723 /*
724  * fileio_flush_control_get_token():
725  *
726  * returns:
727  *
728  * Note:
729  */
730 static int
732 {
733 #if !defined(SERVER_MODE)
734  return NO_ERROR;
735 #else
737  int rv = NO_ERROR;
738  int retry_count = 0;
739  int nreq;
740  bool log_cs_own = false;
741 
742  PERF_UTIME_TRACKER time_tracker = PERF_UTIME_TRACKER_INITIALIZER;
743 
744  if (tb == NULL)
745  {
746  return NO_ERROR;
747  }
748 
749  assert (ntoken > 0);
750 
751  if (LOG_CS_OWN (thread_p))
752  {
753  log_cs_own = true;
754  }
755 
756  nreq = ntoken;
757  while (nreq > 0 && retry_count < 10)
758  {
759  /* try to get a token from share tokens */
760  rv = pthread_mutex_lock (&tb->token_mutex);
761  assert (rv == NO_ERROR);
762 
763  if (log_cs_own == true)
764  {
765  fc_Stats.num_log_pages += nreq;
766  }
767  else
768  {
769  fc_Stats.num_pages += nreq;
770  }
771 
772  if (tb->tokens >= nreq)
773  {
774  tb->tokens -= nreq;
775  tb->token_consumed += nreq;
777  return NO_ERROR;
778  }
779  else if (tb->tokens > 0)
780  {
781  nreq -= tb->tokens;
782  tb->token_consumed += tb->tokens;
783  tb->tokens = 0;
784  }
785 
786  assert (nreq > 0);
787 
788  if (log_cs_own == true)
789  {
791  return NO_ERROR;
792  }
793 
794  PERF_UTIME_TRACKER_START (thread_p, &time_tracker);
795 
796  /* Wait for signal */
797  rv = pthread_cond_wait (&tb->waiter_cond, &tb->token_mutex);
798 
800  retry_count++;
801 
802  PERF_UTIME_TRACKER_BULK_TIME (thread_p, &time_tracker, PSTAT_PB_COMPENSATE_FLUSH, nreq);
803  }
804 
805  /* I am very very unlucky (unlikely to happen) */
806  er_log_debug (ARG_FILE_LINE, "Failed to get token within %d trial (req=%d, remained=%d)", retry_count, ntoken, nreq);
807  return NO_ERROR;
808 #endif
809 }
810 
811 /*
812  * fileio_flush_control_add_tokens():
813  *
814  * returns:
815  *
816  * Note:
817  */
818 int
819 fileio_flush_control_add_tokens (THREAD_ENTRY * thread_p, INT64 diff_usec, int *token_gen, int *token_consumed)
820 {
821 #if !defined(SERVER_MODE)
822  return NO_ERROR;
823 #else
825  int gen_tokens;
826  int rv = NO_ERROR;
827 
828  assert (token_gen != NULL);
829 
830  if (tb == NULL)
831  {
832  return NO_ERROR;
833  }
834 
835  /* add remaining tokens to shared tokens */
836  rv = pthread_mutex_lock (&tb->token_mutex);
837 
838  *token_consumed = tb->token_consumed;
839  tb->token_consumed = 0;
840 
841  perfmon_add_stat (thread_p, PSTAT_FC_NUM_PAGES, fc_Stats.num_pages);
843  perfmon_add_stat (thread_p, PSTAT_FC_TOKENS, fc_Stats.num_tokens);
844 
845 
847  {
848  /* Get desired rate from evaluating changes in last iteration. */
849  gen_tokens = fileio_flush_control_get_desired_rate (tb);
850  /* Check new rate is not below minimum required. */
851  gen_tokens = (int) MAX (gen_tokens, (double) FILEIO_MIN_FLUSH_PAGES_PER_SEC * (double) diff_usec / 1000000.0);
852  }
853  else
854  {
855  /* Always set maximum rate. */
856  gen_tokens = (int) (prm_get_integer_value (PRM_ID_MAX_FLUSH_PAGES_PER_SECOND) * (double) diff_usec / 1000000.0);
857  }
858 
859  *token_gen = gen_tokens;
860 
861  /* initialization statistics */
862  fc_Stats.num_pages = 0;
863  fc_Stats.num_log_pages = 0;
864  fc_Stats.num_tokens = gen_tokens;
865 
866  tb->tokens = gen_tokens;
867 
868  /* signal to waiters */
869  pthread_cond_broadcast (&tb->waiter_cond);
871  return rv;
872 
873 #endif
874 }
875 
876 /*
877  * fileio_flush_control_get_desired_rate () -
878  *
879  */
880 static int
882 {
883 #if !defined (SERVER_MODE)
884  return 0;
885 #else
886  int dirty_rate = pgbuf_flush_control_from_dirty_ratio ();
887  int adjust_rate = fc_Stats.num_tokens; /* Start with previous rate. */
888 
889  if (tb->tokens > 0)
890  {
891  if (dirty_rate > 0)
892  {
893  /* This is difficult situation. We did not consume all tokens but dirty rate goes up. Let's keep the number
894  * of tokens until dirty rate is no longer an issue. */
895  }
896  else
897  {
898  /* Do not drop the tokens too fast. If for any reason flush has been completely stopped, tokens drop to
899  * minimum directly. */
900  adjust_rate -= (int) (tb->tokens * FILEIO_PAGE_FLUSH_DROP_RATE);
901  }
902  }
903  else
904  {
905  /* We need to increase the rate. */
906  adjust_rate += MAX (dirty_rate, (int) (fc_Stats.num_tokens * FILEIO_PAGE_FLUSH_GROW_RATE));
907  }
908  return adjust_rate;
909 #endif
910 }
911 
912 /*
913  * fileio_initialize_volume_info_cache () - Allocate/initialize
914  * volinfo_header.volinfo array
915  * return: 0 if success, or -1
916  *
917  * Note: This function is usually first called by
918  * fileio_find_volume_descriptor_with_label()(normal startup,
919  * backup/restore etc.) or fileio_mount()(database creation time)
920  */
921 static int
923 {
924  int i, n;
925  int rv;
926 
927  rv = pthread_mutex_lock (&fileio_Vol_info_header.mutex);
928 
929  if (fileio_Vol_info_header.volinfo == NULL)
930  {
931  n = (VOLID_MAX - 1) / FILEIO_VOLINFO_INCREMENT + 1;
932  fileio_Vol_info_header.volinfo = (FILEIO_VOLUME_INFO **) malloc (sizeof (FILEIO_VOLUME_INFO *) * n);
933  if (fileio_Vol_info_header.volinfo == NULL)
934  {
936  pthread_mutex_unlock (&fileio_Vol_info_header.mutex);
937  return -1;
938  }
939  fileio_Vol_info_header.num_volinfo_array = n;
940 
941  for (i = 0; i < fileio_Vol_info_header.num_volinfo_array; i++)
942  {
943  fileio_Vol_info_header.volinfo[i] = NULL;
944  }
945  }
946 
947  pthread_mutex_unlock (&fileio_Vol_info_header.mutex);
948  return 0;
949 }
950 
951 /* TODO: check not use */
952 #if 0
953 /*
954  * fileio_final_volinfo_cache () - Free volinfo_header.volinfo array
955  * return: void
956  */
957 void
958 fileio_final_volinfo_cache (void)
959 {
960  int i;
961 #if defined(WINDOWS) && defined(SERVER_MODE)
962  int j;
963  FILEIO_VOLUME_INFO *vf;
964 #endif /* WINDOWS && SERVER_MODE */
965  if (fileio_Vol_info_header.volinfo != NULL)
966  {
967  for (i = 0; i < fileio_Vol_info_header.num_volinfo_array; i++)
968  {
969 #if defined(WINDOWS) && defined(SERVER_MODE)
970  vf = fileio_Vol_info_header.volinfo[i];
971  for (j = 0; j < FILEIO_VOLINFO_INCREMENT; j++)
972  {
973  if (vf[j].vol_mutex != NULL)
974  {
975  pthread_mutex_destroy (&vf[j].vol_mutex);
976  }
977  }
978 #endif /* WINDOWS && SERVER_MODE */
979  free_and_init (fileio_Vol_info_header.volinfo[i]);
980  }
981  free_and_init (fileio_Vol_info_header.volinfo);
982  fileio_Vol_info_header.num_volinfo_array = 0;
983  }
984 }
985 #endif
986 
987 static int
989 {
990  FILEIO_VOLUME_INFO *vol_info_p;
991  int i;
992 
993  header_p->volinfo[idx] = NULL;
994  vol_info_p = (FILEIO_VOLUME_INFO *) malloc (sizeof (FILEIO_VOLUME_INFO) * FILEIO_VOLINFO_INCREMENT);
995  if (vol_info_p == NULL)
996  {
999  return ER_FAILED;
1000  }
1001 
1002  for (i = 0; i < FILEIO_VOLINFO_INCREMENT; i++)
1003  {
1004  vol_info_p[i].volid = NULL_VOLID;
1005  vol_info_p[i].vdes = NULL_VOLDES;
1006  vol_info_p[i].lockf_type = FILEIO_NOT_LOCKF;
1007  vol_info_p[i].vlabel[0] = '\0';
1008 #if defined(WINDOWS)
1009  pthread_mutex_init (&vol_info_p[i].vol_mutex, NULL);
1010 #endif /* WINDOWS */
1011  }
1012 
1013  header_p->volinfo[idx] = vol_info_p;
1014  return NO_ERROR;
1015 }
1016 
1017 /*
1018  * fileio_expand_permanent_volume_info () - Expand io_volinfo chunks to cache
1019  * volid volume information
1020  * return: 0 if success, or -1
1021  * header(in):
1022  * volid(in):
1023  *
1024  * Note: Permanent volume informations are stored from volid 0 to
1025  * header->max_perm_vols. If header->max_perm_vols is less than volid,
1026  * allocate new io_volinfo chunk.
1027  */
1028 static int
1030 {
1031  int from_idx, to_idx;
1032  int rv;
1033 
1034  rv = pthread_mutex_lock (&header_p->mutex);
1035 
1036  from_idx = (header_p->max_perm_vols / FILEIO_VOLINFO_INCREMENT);
1037  to_idx = (volid + 1) / FILEIO_VOLINFO_INCREMENT;
1038 
1039  /* check if to_idx chunks are used for temp volume information */
1040  if (to_idx >= (header_p->num_volinfo_array - 1 - header_p->max_temp_vols / FILEIO_VOLINFO_INCREMENT))
1041  {
1042  pthread_mutex_unlock (&header_p->mutex);
1043  return -1;
1044  }
1045 
1046  for (; from_idx <= to_idx; from_idx++)
1047  {
1048  if (fileio_allocate_and_initialize_volume_info (header_p, from_idx) != NO_ERROR)
1049  {
1050  pthread_mutex_unlock (&header_p->mutex);
1051  return -1;
1052  }
1053 
1054  header_p->max_perm_vols = (from_idx + 1) * FILEIO_VOLINFO_INCREMENT;
1055  }
1056 
1057  pthread_mutex_unlock (&header_p->mutex);
1058  return 0;
1059 }
1060 
1061 /*
1062  * fileio_expand_temporary_volume_info () - Expand io_volinfo chunks to cache
1063  * volid volume information
1064  * return: 0 if success, or -1
1065  * header(in):
1066  * volid(in):
1067  *
1068  * Note: Temporary volume informations are stored from volid LOG_MAX_DBVOLID to
1069  * LOG_MAX_DBVOLID-header->max_temp_vols.
1070  * If LOG_MAX_DBVOLID-header->max_temp_vols is greater than volid,
1071  * allocate new io_volinfo chunk.
1072  */
1073 static int
1075 {
1076  int from_idx, to_idx;
1077  int rv;
1078 
1079  rv = pthread_mutex_lock (&header_p->mutex);
1080 
1081  from_idx = header_p->num_volinfo_array - 1 - (header_p->max_temp_vols / FILEIO_VOLINFO_INCREMENT);
1082  to_idx = header_p->num_volinfo_array - 1 - ((LOG_MAX_DBVOLID - volid) / FILEIO_VOLINFO_INCREMENT);
1083 
1084  /* check if to_idx chunks are used for perm. volume information */
1085  if (to_idx <= (header_p->max_perm_vols - 1) / FILEIO_VOLINFO_INCREMENT)
1086  {
1087  pthread_mutex_unlock (&header_p->mutex);
1088  return -1;
1089  }
1090 
1091  for (; from_idx >= to_idx; from_idx--)
1092  {
1093  if (fileio_allocate_and_initialize_volume_info (header_p, from_idx) != NO_ERROR)
1094  {
1095  pthread_mutex_unlock (&header_p->mutex);
1096  return -1;
1097  }
1098 
1099  header_p->max_temp_vols = (header_p->num_volinfo_array - from_idx) * FILEIO_VOLINFO_INCREMENT;
1100  }
1101 
1102  pthread_mutex_unlock (&header_p->mutex);
1103  return 0;
1104 }
1105 
1106 /* TODO: recoding to use APR
1107  *
1108  * fileio_ctime() - VARIANT OF NORMAL CTIME THAT ALWAYS REMOVES THE NEWLINE
1109  * return: ptr to time string returned by ctime
1110  * time_t(in):
1111  * buf(in):
1112  *
1113  * Note: Strips the \n off the end of the string returned by ctime.
1114  * this routine is really general purpose, there may be other users
1115  * of ctime.
1116  */
1117 static char *
1118 fileio_ctime (INT64 * clock_p, char *buffer_p)
1119 {
1120  char *p, *t;
1121  time_t tmp_time;
1122 
1123  tmp_time = (time_t) (*clock_p);
1124  t = ctime_r (&tmp_time, buffer_p);
1125 
1126  p = strchr (t, '\n');
1127  if (p)
1128  {
1129  *p = '\0';
1130  }
1131 
1132  return (t);
1133 }
1134 
1135 /*
1136  * fileio_is_terminated_process () -
1137  * return:
1138  * pid(in):
1139  */
1140 static bool
1142 {
1143 #if defined(WINDOWS)
1144  HANDLE h_process;
1145 
1146  h_process = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid);
1147  if (h_process == NULL)
1148  {
1149  return true;
1150  }
1151  else
1152  {
1153  CloseHandle (h_process);
1154  return false;
1155  }
1156 #else /* WINDOWS */
1157  if (kill (pid, 0) == -1)
1158  {
1159  return true;
1160  }
1161  else
1162  {
1163  return false;
1164  }
1165 #endif /* WINDOWS */
1166 }
1167 
1168 #if !defined(WINDOWS)
1169 /*
1170  * fileio_lock () - LOCKF A DATABASE VOLUME
1171  * return:
1172  * db_fullname(in): Name of the database where the volume belongs
1173  * vlabel(in): Volume label
1174  * vdes(in): Volume descriptor
1175  * dowait(in): true when it is ok to wait for the lock (databases.txt)
1176  *
1177  */
1178 static FILEIO_LOCKF_TYPE
1179 fileio_lock (const char *db_full_name_p, const char *vol_label_p, int vol_fd, bool dowait)
1180 {
1181  FILE *fp;
1182  char name_info_lock[PATH_MAX];
1183  char host[CUB_MAXHOSTNAMELEN];
1184  char host2[CUB_MAXHOSTNAMELEN];
1185  char user[FILEIO_USER_NAME_SIZE];
1186  char login_name[FILEIO_USER_NAME_SIZE];
1187  INT64 lock_time;
1188  long long tmp_lock_time;
1189  int pid;
1190  bool retry = true;
1191  int lockf_errno;
1193  int total_num_loops = 0;
1194  int num_loops = 0;
1195  int max_num_loops;
1196  char io_timeval[CTIME_MAX], format_string[32];
1197 
1199  {
1200  return FILEIO_LOCKF;
1201  }
1202 
1203 #if defined(CUBRID_DEBUG)
1204  struct stat stbuf;
1205 
1206  /*
1207  * Make sure that advisory locks are used. An advisory lock is desired
1208  * since we are observing a voluntarily locking scheme.
1209  * Mandatory locks are know to be dangerous. If a runaway or otherwise
1210  * out-of-control process should hold a mandatory lock on the database
1211  * and fail to release that lock, the entire database system could hang
1212  */
1213  if (fstat (vol_fd, &stbuf) != -1)
1214  {
1215  if ((stbuf.st_mode & S_ISGID) != 0 && (stbuf.st_mode & S_IRWXG) != S_IXGRP)
1216  {
1217  er_log_debug (ARG_FILE_LINE, "A mandatory lock will be set on file = %s", vol_label_p);
1218  }
1219  }
1220 #endif /* CUBRID_DEBUG */
1221 
1222  if (vol_label_p == NULL)
1223  {
1224  vol_label_p = "";
1225  }
1226 
1227  max_num_loops = FILEIO_MAX_WAIT_DBTXT;
1228  fileio_make_volume_lock_name (name_info_lock, vol_label_p);
1229 
1230  /*
1231  * NOTE: The lockby auxiliary file is created only after we have acquired
1232  * the lock. This is important to avoid a possible synchronization
1233  * problem with this secundary technique
1234  */
1235 
1236  sprintf (format_string, "%%%ds %%d %%%ds %%lld", FILEIO_USER_NAME_SIZE - 1, CUB_MAXHOSTNAMELEN - 1);
1237 
1238 again:
1239  while (retry == true && fileio_lock_file_write (vol_fd, 0, SEEK_SET, 0) < 0)
1240  {
1241  if (errno == EINTR)
1242  {
1243  /* Retry if the an interruption was signed */
1244  retry = true;
1245  continue;
1246  }
1247  lockf_errno = errno;
1248  retry = false;
1249 
1250  /* Volume seems to be mounted by someone else. Find out who has it. */
1251  fp = fopen (name_info_lock, "r");
1252  if (fp == NULL)
1253  {
1254  (void) sleep (3);
1255  num_loops += 3;
1256  total_num_loops += 3;
1257  fp = fopen (name_info_lock, "r");
1258  if (fp == NULL && num_loops <= 3)
1259  {
1260  /*
1261  * Note that we try to check for the lock only one more time,
1262  * unless we have been waiting for a while
1263  * (Case of dowait == false,
1264  * note that num_loops is set to 0 when waiting for a lock).
1265  */
1266  retry = true;
1267  continue;
1268  }
1269  }
1270 
1271  if (fp == NULL || fscanf (fp, format_string, user, &pid, host, &tmp_lock_time) != 4)
1272  {
1273  strcpy (user, "???");
1274  strcpy (host, "???");
1275  pid = 0;
1276  lock_time = 0;
1277  }
1278  else
1279  {
1280  lock_time = tmp_lock_time;
1281  }
1282  /* Make sure that the process holding the lock is not a run away process. A run away process is one of the
1283  * following: 1) If the lockby file exist and the following is true: same user, same host, and lockby process
1284  * does not exist any longer */
1285  if (fp == NULL)
1286  {
1287  /* It is no more true that if the lockby file does not exist, then it is the run away process. When the user
1288  * cannot get the file lock, it means that the another process who owns the database exists. */
1289  fileio_ctime (&lock_time, io_timeval);
1290  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_MOUNT_LOCKED, 6, vol_label_p, db_full_name_p, user, pid, host,
1291  (lock_time == 0) ? "???" : io_timeval);
1292  return FILEIO_NOT_LOCKF;
1293  }
1294  else
1295  {
1296  (void) fclose (fp);
1297  *host2 = '\0';
1298  cuserid ((char *) login_name);
1299 
1300  login_name[FILEIO_USER_NAME_SIZE - 1] = '\0';
1301 
1302  if (!
1303  (strcmp (user, login_name) == 0 && GETHOSTNAME (host2, CUB_MAXHOSTNAMELEN) == 0
1304  && strcmp (host, host2) == 0 && fileio_is_terminated_process (pid) != 0 && errno == ESRCH))
1305  {
1306  if (dowait != false)
1307  {
1308  /*
1309  * NOBODY USES dowait EXPECT DATABASE.TXT
1310  *
1311  * It would be nice if we could use a wait function to wait on a
1312  * process that is not a child process.
1313  * Wait until the process is gone if we are in the same machine,
1314  * otherwise, continue looping.
1315  */
1316  while (fileio_is_volume_exist (name_info_lock) == true && num_loops < 60
1317  && total_num_loops < max_num_loops)
1318  {
1319  if (strcmp (host, host2) == 0 && fileio_is_terminated_process (pid) != 0)
1320  {
1321  break;
1322  }
1323 
1324  (void) sleep (3);
1325  num_loops += 3;
1326  total_num_loops += 3;
1327  }
1328 
1329  if (total_num_loops < max_num_loops)
1330  {
1331  retry = true;
1332  num_loops = 0;
1333  goto again;
1334  }
1335  }
1336 
1337  /* not a run away process */
1338  fileio_ctime (&lock_time, io_timeval);
1339  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_MOUNT_LOCKED, 6, vol_label_p, db_full_name_p, user, pid,
1340  host, io_timeval);
1341  return FILEIO_NOT_LOCKF;
1342  }
1343  }
1344 #if defined(CUBRID_DEBUG)
1346  "io_lock: WARNING ignoring a run away lock on volume = %s\n. lockd deamon may not be"
1347  " working right.\n UNIX error = %s", vol_label_p, strerror (lockf_errno));
1348 #endif /* CUBRID_DEBUG */
1349  }
1350 
1351  /* Create the information lock file and write the information about the lock */
1352  fp = fopen (name_info_lock, "w");
1353  if (fp != NULL)
1354  {
1355  if (GETHOSTNAME (host, CUB_MAXHOSTNAMELEN) != 0)
1356  {
1357  strcpy (host, "???");
1358  }
1359 
1360  if (getuserid (login_name, FILEIO_USER_NAME_SIZE) == NULL)
1361  {
1362  strcpy (login_name, "???");
1363  }
1364 
1365  (void) fprintf (fp, "%s %d %s %ld", login_name, (int) GETPID (), host, time (NULL));
1366  (void) fclose (fp);
1367  }
1368  else
1369  {
1370  /* Unable to create the lockf file. */
1371  if (result == FILEIO_LOCKF)
1372  {
1374  fileio_unlock (vol_label_p, vol_fd, result);
1375  result = FILEIO_NOT_LOCKF;
1376  }
1377  }
1378 
1379  return result;
1380 }
1381 
1382 /*
1383  * fileio_lock_la_log_path () - LOCKF A applylogdb logpath lock
1384  * return:
1385  * db_fullname(in): Name of the database where the volume belongs
1386  * lock_path(in): Lock file path
1387  * vdes(in): Volume descriptor
1388  * last_deleted_arv_num(out):
1389  *
1390  */
1392 fileio_lock_la_log_path (const char *db_full_name_p, const char *lock_path_p, int vol_fd, int *last_deleted_arv_num)
1393 {
1394  FILE *fp;
1395  char host[CUB_MAXHOSTNAMELEN];
1396  char user[FILEIO_USER_NAME_SIZE];
1397  char login_name[FILEIO_USER_NAME_SIZE];
1398  INT64 lock_time;
1399  long long tmp_lock_time;
1400  int pid;
1401  bool retry = true;
1402  int lockf_errno;
1404  int num_loops = 0;
1405  char io_timeval[64], format_string[32];
1406 
1407 #if defined(CUBRID_DEBUG)
1408  struct stat stbuf;
1409 
1410  /*
1411  * Make sure that advisory locks are used. An advisory lock is desired
1412  * since we are observing a voluntarily locking scheme.
1413  * Mandatory locks are know to be dangerous. If a runaway or otherwise
1414  * out-of-control process should hold a mandatory lock on the database
1415  * and fail to release that lock, the entire database system could hang
1416  */
1417  if (fstat (vol_fd, &stbuf) != -1)
1418  {
1419  if ((stbuf.st_mode & S_ISGID) != 0 && (stbuf.st_mode & S_IRWXG) != S_IXGRP)
1420  {
1421  er_log_debug (ARG_FILE_LINE, "A mandatory lock will be set on file = %s", vol_label_p);
1422  }
1423  }
1424 #endif /* CUBRID_DEBUG */
1425 
1426  if (lock_path_p == NULL)
1427  {
1428  lock_path_p = "";
1429  }
1430 
1431  /*
1432  * NOTE: The lockby auxiliary file is created only after we have acquired
1433  * the lock. This is important to avoid a possible synchronization
1434  * problem with this secundary technique
1435  */
1436  sprintf (format_string, "%%d %%%ds %%d %%%ds %%lld", FILEIO_USER_NAME_SIZE - 1, CUB_MAXHOSTNAMELEN - 1);
1437 
1438  while (retry == true && fileio_lock_file_write (vol_fd, 0, SEEK_SET, 0) < 0)
1439  {
1440  if (errno == EINTR)
1441  {
1442  /* Retry if the an interruption was signed */
1443  retry = true;
1444  continue;
1445  }
1446  lockf_errno = errno;
1447  retry = false;
1448 
1449  /* Volume seems to be mounted by someone else. Find out who has it. */
1450  fp = fopen (lock_path_p, "r");
1451  if (fp == NULL)
1452  {
1453  (void) sleep (3);
1454  num_loops += 3;
1455  fp = fopen (lock_path_p, "r");
1456  if (fp == NULL && num_loops <= 3)
1457  {
1458  retry = true;
1459  continue;
1460  }
1461  }
1462 
1463  if (fp == NULL || fscanf (fp, format_string, last_deleted_arv_num, user, &pid, host, &tmp_lock_time) != 5)
1464  {
1465  strcpy (user, "???");
1466  strcpy (host, "???");
1467  pid = 0;
1468  lock_time = 0;
1469  *last_deleted_arv_num = -1;
1470  }
1471  else
1472  {
1473  lock_time = tmp_lock_time;
1474  }
1475 
1476  if (fp != NULL)
1477  {
1478  (void) fclose (fp);
1479  }
1480 #if defined(CUBRID_DEBUG)
1482  "io_lock: WARNING ignoring a run away lock on volume = %s\n. lockd deamon may not be"
1483  " working right.\n UNIX error = %s", lock_path_p, strerror (lockf_errno));
1484 #endif /* CUBRID_DEBUG */
1485 
1486  memset (io_timeval, 0, sizeof (io_timeval));
1487  fileio_ctime (&lock_time, io_timeval);
1488  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_MOUNT_LOCKED, 6, lock_path_p, db_full_name_p, user, pid, host,
1489  (lock_time == 0) ? "???" : io_timeval);
1490  return FILEIO_NOT_LOCKF;
1491  }
1492 
1493  /* Create the information lock file and write the information about the lock */
1494  fp = fdopen (vol_fd, "w+");
1495  if (fp != NULL)
1496  {
1497  if (fscanf (fp, format_string, last_deleted_arv_num, user, &pid, host, &tmp_lock_time) != 5)
1498  {
1499  *last_deleted_arv_num = -1;
1500  }
1501 
1502  fseek (fp, 0, SEEK_SET);
1503 
1504  if (GETHOSTNAME (host, CUB_MAXHOSTNAMELEN) != 0)
1505  {
1506  strcpy (host, "???");
1507  }
1508 
1509  if (getuserid (login_name, FILEIO_USER_NAME_SIZE) == NULL)
1510  {
1511  strcpy (login_name, "???");
1512  }
1513 
1514  if (*last_deleted_arv_num < 0)
1515  {
1516  *last_deleted_arv_num = -1;
1517  }
1518 
1519  (void) fprintf (fp, "%-10d %s %d %s %ld", *last_deleted_arv_num, login_name, (int) GETPID (), host, time (NULL));
1520  fflush (fp);
1521  }
1522  else
1523  {
1524  /* Unable to create the lockf file. */
1525  if (result == FILEIO_LOCKF)
1526  {
1528  result = FILEIO_NOT_LOCKF;
1529  }
1530  }
1531 
1532  return result;
1533 }
1534 
1535 /*
1536  * fileio_lock_la_dbname () - LOCKF A applylogdb database lock
1537  * return:
1538  *
1539  * lockf_vdes(in): lock file descriptor
1540  * db_name(in): database name
1541  * log_path(in): log file path
1542  *
1543  */
1545 fileio_lock_la_dbname (int *lockf_vdes, char *db_name, char *log_path)
1546 {
1547  int error = NO_ERROR;
1548  int fd = NULL_VOLDES;
1549  int pid;
1550  int r;
1552  FILE *fp = NULL;
1553  char lock_dir[PATH_MAX], lock_path[PATH_MAX];
1554  char tmp_db_name[DB_MAX_IDENTIFIER_LENGTH], tmp_log_path[PATH_MAX];
1555  char format_string[PATH_MAX];
1556 
1557  envvar_vardir_file (lock_dir, sizeof (lock_dir), "APPLYLOGDB");
1558  if (snprintf (lock_path, sizeof (lock_path) - 1, "%s/%s", lock_dir, db_name) < 0)
1559  {
1560  assert (false);
1561  result = FILEIO_NOT_LOCKF;
1562  goto error_return;
1563  }
1564 
1565  if (access (lock_dir, F_OK) < 0)
1566  {
1567  /* create parent directory if not exist */
1568  if (mkdir (lock_dir, 0777) < 0 && errno == ENOENT)
1569  {
1570  char pdir[PATH_MAX];
1571 
1572  if (cub_dirname_r (lock_dir, pdir, PATH_MAX) > 0 && access (pdir, F_OK) < 0)
1573  {
1574  mkdir (pdir, 0777);
1575  }
1576  }
1577  }
1578 
1579  if (access (lock_dir, F_OK) < 0)
1580  {
1581  if (mkdir (lock_dir, 0777) < 0)
1582  {
1583  er_log_debug (ARG_FILE_LINE, "unable to create dir (%s)", lock_dir);
1585  result = FILEIO_NOT_LOCKF;
1586  goto error_return;
1587  }
1588  }
1589 
1590  snprintf (format_string, sizeof (format_string), "%%d %%%ds %%%ds", DB_MAX_IDENTIFIER_LENGTH - 1, PATH_MAX - 1);
1591 
1592  fd = fileio_open (lock_path, O_RDWR | O_CREAT, 0644);
1593  if (fd == NULL_VOLDES)
1594  {
1595  er_log_debug (ARG_FILE_LINE, "unable to open lock_file (%s)", lock_path);
1597 
1598  result = FILEIO_NOT_LOCKF;
1599  goto error_return;
1600  }
1601 
1602  fp = fopen (lock_path, "r");
1603  if (fp)
1604  {
1605  fseek (fp, (off_t) 0, SEEK_SET);
1606 
1607  r = fscanf (fp, format_string, &pid, tmp_db_name, tmp_log_path);
1608  if (r == 3)
1609  {
1610  assert_release (strcmp (db_name, tmp_db_name) == 0);
1611 
1612  if (strcmp (db_name, tmp_db_name) || strcmp (log_path, tmp_log_path))
1613  {
1614  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_MOUNT_LOCKED, 6, lock_path, db_name, "-", pid, "-", "-");
1615 
1616  fclose (fp);
1617 
1618  result = FILEIO_NOT_LOCKF;
1619  goto error_return;
1620  }
1621  }
1622 
1623  fclose (fp);
1624  }
1625  else
1626  {
1627  er_log_debug (ARG_FILE_LINE, "unable to open lock_file (%s)", lock_path);
1629 
1630  result = FILEIO_NOT_LOCKF;
1631  goto error_return;
1632  }
1633 
1634  if (fileio_lock_file_write (fd, 0, SEEK_SET, 0) < 0)
1635  {
1636  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_MOUNT_LOCKED, 6, lock_path, db_name, "-", 0, "-", "-");
1637 
1638  result = FILEIO_NOT_LOCKF;
1639  goto error_return;
1640  }
1641 
1642  fp = fopen (lock_path, "w+");
1643  if (fp)
1644  {
1645  fseek (fp, (off_t) 0, SEEK_SET);
1646 
1647  pid = getpid ();
1648  fprintf (fp, "%-10d %s %s", pid, db_name, log_path);
1649  fflush (fp);
1650  fclose (fp);
1651  }
1652  else
1653  {
1654  error = fileio_release_lock (fd);
1655  assert_release (error == NO_ERROR);
1656 
1657  er_log_debug (ARG_FILE_LINE, "unable to open lock_file (%s)", lock_path);
1659 
1660  result = FILEIO_NOT_LOCKF;
1661  goto error_return;
1662  }
1663 
1664  (*lockf_vdes) = fd;
1665 
1666  return result;
1667 
1668 error_return:
1669 
1670  if (fd != NULL_VOLDES)
1671  {
1672  fileio_close (fd);
1673  fd = NULL_VOLDES;
1674  }
1675 
1676  (*lockf_vdes) = fd;
1677 
1678  return result;
1679 }
1680 
1681 /*
1682  * fileio_unlock_la_dbname () - UNLOCKF A applylogdb database lock
1683  * return:
1684  *
1685  * lockf_vdes(in): lock file descriptor
1686  * db_name(in): database name
1687  * clear_owner(in): clear lock owner
1688  *
1689  */
1691 fileio_unlock_la_dbname (int *lockf_vdes, char *db_name, bool clear_owner)
1692 {
1693  FILEIO_LOCKF_TYPE result;
1694  int error;
1695  off_t end_offset;
1696  FILE *fp = NULL;
1697  char lock_dir[PATH_MAX], lock_path[PATH_MAX];
1698 
1699  envvar_vardir_file (lock_dir, sizeof (lock_dir), "APPLYLOGDB");
1700  if (snprintf (lock_path, sizeof (lock_path) - 1, "%s/%s", lock_dir, db_name) < 0)
1701  {
1702  assert (false);
1703  return FILEIO_NOT_LOCKF;
1704  }
1705 
1706  if (access (lock_dir, F_OK) < 0)
1707  {
1708  er_log_debug (ARG_FILE_LINE, "lock directory does not exist (%s)", lock_dir);
1710  return FILEIO_NOT_LOCKF;
1711  }
1712 
1713  assert_release ((*lockf_vdes) != NULL_VOLDES);
1714  if ((*lockf_vdes) == NULL_VOLDES)
1715  {
1716  return FILEIO_NOT_LOCKF;
1717  }
1718 
1719  if (clear_owner)
1720  {
1721  fp = fopen (lock_path, "w+");
1722  if (fp == NULL)
1723  {
1724  er_log_debug (ARG_FILE_LINE, "unable to open lock_file (%s)", lock_path);
1726 
1727  return FILEIO_LOCKF;
1728  }
1729 
1730  fseek (fp, (off_t) 0, SEEK_END);
1731  end_offset = ftell (fp);
1732  fseek (fp, (off_t) 0, SEEK_SET);
1733 
1734  if (end_offset > 0)
1735  {
1736  fprintf (fp, "%*s", (int) end_offset, " ");
1737  }
1738  fflush (fp);
1739  fclose (fp);
1740  }
1741 
1742  error = fileio_release_lock ((*lockf_vdes));
1743  if (error == NO_ERROR)
1744  {
1745  result = FILEIO_NOT_LOCKF;
1746  }
1747  else
1748  {
1749  assert_release (error == NO_ERROR);
1750  result = FILEIO_LOCKF;
1751  }
1752 
1753  if (result == FILEIO_NOT_LOCKF)
1754  {
1755  fileio_close ((*lockf_vdes));
1756  (*lockf_vdes) = NULL_VOLDES;
1757  }
1758 
1759  return result;
1760 }
1761 
1762 static void
1763 fileio_check_lockby_file (char *name_info_lock_p)
1764 {
1765  /*
1766  * Either we did not acuire the lock through flock or seek has failed.
1767  * Use secundary technique for verification.
1768  * Make sure that current process has the lock, that is, check if
1769  * these are the consecuences of a run away process. If the lockby file
1770  * indicates that current process has the lock, remove the lockby file
1771  * to indicate that the process does not have the lock any longer.
1772  */
1773  FILE *fp;
1774  int pid;
1775  char login_name[FILEIO_USER_NAME_SIZE];
1776  char user[FILEIO_USER_NAME_SIZE];
1777  char host[CUB_MAXHOSTNAMELEN];
1778  char host2[CUB_MAXHOSTNAMELEN];
1779  char format_string[32];
1780 
1781  fp = fopen (name_info_lock_p, "r");
1782  if (fp != NULL)
1783  {
1784  sprintf (format_string, "%%%ds %%d %%%ds", FILEIO_USER_NAME_SIZE - 1, CUB_MAXHOSTNAMELEN - 1);
1785  if (fscanf (fp, format_string, user, &pid, host) != 3)
1786  {
1787  strcpy (user, "???");
1788  strcpy (host, "???");
1789  pid = 0;
1790  }
1791  (void) fclose (fp);
1792 
1793  /* Check for same process, same user, same host */
1794  getuserid (login_name, FILEIO_USER_NAME_SIZE);
1795 
1796  if (pid == GETPID () && strcmp (user, login_name) == 0 && GETHOSTNAME (host2, CUB_MAXHOSTNAMELEN) == 0
1797  && strcmp (host, host2) == 0)
1798  {
1799  (void) remove (name_info_lock_p);
1800  }
1801  }
1802 }
1803 
1804 /*
1805  * fileio_unlock () - UNLOCK A DATABASE VOLUME
1806  * return: void
1807  * vlabel(in): Volume label
1808  * vdes(in): Volume descriptor
1809  * lockf_type(in): Type of lock
1810  *
1811  * Note: The volume associated with the given name is unlocked and the
1812  * lock information file is removed.
1813  * If the Unix system complains that the volume is not locked by
1814  * the requested process, the information lock file is consulted
1815  * to verify for run a way process. If the requested process is
1816  * identical to the one recorded in the information lock, the
1817  * function returns without any error, otherwise, an error is set
1818  * and an error condition is returned.
1819  */
1820 static void
1821 fileio_unlock (const char *vol_label_p, int vol_fd, FILEIO_LOCKF_TYPE lockf_type)
1822 {
1823  char name_info_lock[PATH_MAX];
1824 
1826  {
1827  if (vol_label_p == NULL)
1828  {
1829  vol_label_p = "";
1830  }
1831 
1832  strcpy (name_info_lock, vol_label_p);
1833  fileio_make_volume_lock_name (name_info_lock, vol_label_p);
1834 
1835  /*
1836  * We must remove the lockby file before we call flock to unlock the file.
1837  * Otherwise, we may remove the file when is locked by another process
1838  * Case of preemption and another process acquiring the lock.
1839  */
1840 
1841  if (lockf_type != FILEIO_LOCKF)
1842  {
1843  fileio_check_lockby_file (name_info_lock);
1844  }
1845  else
1846  {
1847  (void) remove (name_info_lock);
1848  fileio_unlock_file (vol_fd, 0, SEEK_SET, 0);
1849  }
1850  }
1851 }
1852 #endif /* !WINDOWS */
1853 
1854 /*
1855  * fileio_initialize_pages () - Initialize the first npages of the given volume with the
1856  * content of given page
1857  * return: io_pgptr on success, NULL on failure
1858  * vdes(in): Volume descriptor
1859  * io_pgptr(in): Initialization content of all pages
1860  * npages(in): Number of pages to initialize
1861  * kbytes_to_be_written_per_sec : size to add volume per sec
1862  */
1863 void *
1864 fileio_initialize_pages (THREAD_ENTRY * thread_p, int vol_fd, FILEIO_PAGE * io_page_p, DKNPAGES start_pageid,
1865  DKNPAGES npages, size_t page_size, int kbytes_to_be_written_per_sec)
1866 {
1867  PAGEID page_id;
1868  bool skip_flush = false;
1869 #if defined (SERVER_MODE)
1870  int count_of_page_for_a_sleep = 10;
1871  INT64 allowed_millis_for_a_sleep = 0; /* time which is time for writing unit of page and sleeping in a sleep */
1872  INT64 previous_elapsed_millis; /* time which is previous time for writing unit of page and sleep */
1873  INT64 time_to_sleep;
1874 
1875  TSC_TICKS start_tick, end_tick;
1876  TSCTIMEVAL tv_diff;
1877 
1878  INT64 page_count_per_sec;
1879 #endif
1880 
1881 #if defined (SERVER_MODE)
1882  if (kbytes_to_be_written_per_sec > 0)
1883  {
1884  page_count_per_sec = kbytes_to_be_written_per_sec / (IO_PAGESIZE / ONE_K);
1885 
1886  if (page_count_per_sec < count_of_page_for_a_sleep)
1887  {
1888  page_count_per_sec = count_of_page_for_a_sleep;
1889  }
1890  allowed_millis_for_a_sleep = count_of_page_for_a_sleep * 1000 / page_count_per_sec;
1891 
1892  tsc_getticks (&start_tick);
1893  }
1894 #endif
1895 
1896 #if !defined (CS_MODE)
1897  skip_flush = dwb_is_created ();
1898 #endif
1899 
1900  for (page_id = start_pageid; page_id < npages + start_pageid; page_id++)
1901  {
1902 #if !defined(CS_MODE)
1903  /* check for interrupts from user (i.e. Ctrl-C) */
1904  if ((page_id % FILEIO_CHECK_FOR_INTERRUPT_INTERVAL) == 0)
1905  {
1906  if (logtb_get_check_interrupt (thread_p) && pgbuf_is_log_check_for_interrupts (thread_p))
1907  {
1908  return NULL;
1909  }
1910  }
1911 #endif /* !CS_MODE */
1912 
1913 #if !defined(NDEBUG)
1914  /* skip volume header page to find abnormal update */
1915  if (page_id == 0)
1916  {
1917  continue;
1918  }
1919 #endif
1920 
1921  if (fileio_write_or_add_to_dwb (thread_p, vol_fd, io_page_p, page_id, page_size) == NULL)
1922  {
1923  return NULL;
1924  }
1925 
1926 #if defined (SERVER_MODE)
1927  if (kbytes_to_be_written_per_sec > 0 && (page_id + 1) % count_of_page_for_a_sleep == 0)
1928  {
1929  tsc_getticks (&end_tick);
1930  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
1931 
1932  previous_elapsed_millis = (tv_diff.tv_sec * 1000LL) + (tv_diff.tv_usec / 1000LL);
1933 
1934  /* calculate time to sleep through subtracting */
1935  time_to_sleep = allowed_millis_for_a_sleep - previous_elapsed_millis;
1936  if (time_to_sleep > 0)
1937  {
1938  thread_sleep ((double) time_to_sleep);
1939  }
1940 
1941  tsc_getticks (&start_tick);
1942  }
1943 #endif
1944  }
1945 
1946  return io_page_p;
1947 }
1948 
1949 /*
1950  * fileio_open () - Same as Unix open, but with retry during interrupts
1951  * return: volume descriptor identifier on success, NULL_VOLDES on failure
1952  * vlabel(in): Volume label
1953  * flags(in): open the volume as specified by the flags
1954  * mode(in): used when the volume is created
1955  */
1956 int
1957 fileio_open (const char *vol_label_p, int flags, int mode)
1958 {
1959  int vol_fd;
1960 
1961  do
1962  {
1963 #if defined(WINDOWS)
1964  vol_fd = open (vol_label_p, flags | _O_BINARY, mode);
1965 #else /* WINDOWS */
1966  vol_fd = open (vol_label_p, flags, mode);
1967 #endif /* WINDOWS */
1968  }
1969  while (vol_fd == NULL_VOLDES && errno == EINTR);
1970 
1971 #if !defined(WINDOWS)
1972  if (vol_fd > NULL_VOLDES)
1973  {
1974  int high_vol_fd;
1975  int range = MAX_NTRANS + 10;
1976 
1977  /* move fd to the over max_clients range */
1978  high_vol_fd = fcntl (vol_fd, F_DUPFD, range);
1979  if (high_vol_fd != -1)
1980  {
1981  close (vol_fd);
1982  vol_fd = high_vol_fd;
1983  }
1984  }
1985 
1986  if (prm_get_bool_value (PRM_ID_DBFILES_PROTECT) == true && vol_fd > 0)
1987  {
1988  fileio_get_lock (vol_fd, vol_label_p);
1989  }
1990 #endif /* !WINDOWS */
1991 
1992  return vol_fd;
1993 }
1994 
1995 #if !defined(WINDOWS)
1996 /*
1997  * fileio_set_permission () -
1998  * return:
1999  * vlabel(in):
2000  */
2001 int
2002 fileio_set_permission (const char *vol_label_p)
2003 {
2004  int mode;
2005  struct stat buf;
2006  int error = NO_ERROR;
2007 
2008  if (stat (vol_label_p, &buf) < 0)
2009  {
2011  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, vol_label_p);
2012  return error;
2013  }
2014 
2015  /* get currently set mode */
2016  mode = buf.st_mode;
2017  /* remove group execute permission from mode */
2018  mode &= ~(S_IEXEC >> 3);
2019  /* set 'set group id bit' in mode */
2020  mode |= S_ISGID;
2021 
2022  if (chmod (vol_label_p, mode) < 0)
2023  {
2025  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, vol_label_p);
2026  return error;
2027  }
2028 
2029  return error;
2030 }
2031 
2032 /*
2033  * fileio_get_lock () -
2034  * return:
2035  * fd(in):
2036  * vlabel(in):
2037  */
2038 static int
2039 fileio_get_lock (int fd, const char *vol_label_p)
2040 {
2041  int error = NO_ERROR;
2042 
2043  if (fileio_lock_file_read (fd, 0, SEEK_SET, 0) < 0)
2044  {
2045  error = ER_IO_GET_LOCK_FAIL;
2046  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, vol_label_p, fd);
2047  }
2048 
2049  return error;
2050 }
2051 
2052 /*
2053  * fileio_release_lock () -
2054  * return:
2055  * fd(in):
2056  */
2057 static int
2059 {
2060  int error = NO_ERROR;
2061 
2062  if (fileio_unlock_file (fd, 0, SEEK_SET, 0) < 0)
2063  {
2064  error = ER_IO_RELEASE_LOCK_FAIL;
2066  }
2067 
2068  return error;
2069 }
2070 #endif /* !WINDOWS */
2071 
2072 /*
2073  * fileio_close () - Close the volume associated with the given volume descriptor
2074  * return: void
2075  * vdes(in): Volume descriptor
2076  */
2077 void
2078 fileio_close (int vol_fd)
2079 {
2080 #if !defined(WINDOWS)
2082  {
2083  fileio_release_lock (vol_fd);
2084  }
2085 #endif /* !WINDOWS */
2086 
2087  if (close (vol_fd) != 0)
2088  {
2091  }
2092 }
2093 
2094 /*
2095  * fileio_create () - Create the volume (or file) without initializing it
2096  * return: volume descriptor identifier on success, NULL_VOLDES on failure
2097  * db_fullname(in): Name of the database where the volume belongs
2098  * vlabel(in): Volume label
2099  * volid(in): Volume identifier
2100  * dolock(in): Lock the volume from other Unix processes
2101  * dosync(in): synchronize the writes on the volume ?
2102  */
2103 static int
2104 fileio_create (THREAD_ENTRY * thread_p, const char *db_full_name_p, const char *vol_label_p, VOLID vol_id,
2105  bool is_do_lock, bool is_do_sync)
2106 {
2107  int tmp_vol_desc = NULL_VOLDES;
2108  int vol_fd;
2109  FILEIO_LOCKF_TYPE lockf_type = FILEIO_NOT_LOCKF;
2110 #if defined(WINDOWS)
2111  int sh_flag;
2112 #else
2113  int o_sync;
2114 #endif /* WINDOWS */
2115 
2116 #if !defined(CS_MODE)
2117  /* Make sure that the volume is not already mounted. if it is, dismount the volume. */
2118  vol_fd = fileio_find_volume_descriptor_with_label (vol_label_p);
2119  if (vol_fd != NULL_VOLDES)
2120  {
2121  fileio_dismount (thread_p, vol_fd);
2122  }
2123 #endif /* !CS_MODE */
2124 
2125 #if defined(WINDOWS)
2126  sh_flag = is_do_lock ? _SH_DENYWR : _SH_DENYNO;
2127 
2128  vol_fd = _sopen (vol_label_p, FILEIO_DISK_FORMAT_MODE | O_BINARY, sh_flag, FILEIO_DISK_PROTECTION_MODE);
2129  if (vol_fd == NULL_VOLDES)
2130  {
2131  if (sh_flag == _SH_DENYRW && errno != ENOENT)
2132  {
2133  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_MOUNT_LOCKED, 6, vol_label_p, db_full_name_p,
2134  "-", 0, "-", "-");
2135  }
2136  else
2137  {
2139  }
2140  }
2141 
2142 #else /* !WINDOWS */
2143 
2144  o_sync = (is_do_sync != false) ? O_SYNC : 0;
2145 
2146  /* If the file exist make sure that nobody else is using it, before it is truncated */
2147  if (is_do_lock != false)
2148  {
2149  tmp_vol_desc = fileio_open (vol_label_p, O_RDWR | o_sync, 0);
2150  if (tmp_vol_desc != NULL_VOLDES)
2151  {
2152  /* The volume (file) already exist. Make sure that nobody is using it before the old one is destroyed */
2153  lockf_type = fileio_lock (db_full_name_p, vol_label_p, tmp_vol_desc, false);
2154  if (lockf_type == FILEIO_NOT_LOCKF)
2155  {
2156  /* Volume seems to be mounted by someone else */
2157  fileio_close (tmp_vol_desc);
2158  return NULL_VOLDES;
2159  }
2160  }
2161  }
2162 
2163  vol_fd = fileio_open (vol_label_p, FILEIO_DISK_FORMAT_MODE | o_sync, FILEIO_DISK_PROTECTION_MODE);
2164  if (vol_fd == NULL_VOLDES)
2165  {
2167  }
2168 
2169  if (tmp_vol_desc != NULL_VOLDES)
2170  {
2171  if (lockf_type != FILEIO_NOT_LOCKF)
2172  {
2173  fileio_unlock (vol_label_p, tmp_vol_desc, lockf_type);
2174  }
2175  fileio_close (tmp_vol_desc);
2176  }
2177 #endif /* WINDOWS */
2178 
2180 
2181  if (vol_fd != NULL_VOLDES)
2182  {
2183 #if !defined(WINDOWS)
2184  if (is_do_lock == true)
2185  {
2186  lockf_type = fileio_lock (db_full_name_p, vol_label_p, vol_fd, false);
2187 
2188  if (lockf_type == FILEIO_NOT_LOCKF)
2189  {
2190  /* This should not happen, the volume seems to be mounted by someone else */
2191  fileio_dismount (thread_p, vol_fd);
2192  fileio_unformat (thread_p, vol_label_p);
2193  vol_fd = NULL_VOLDES;
2194 
2195  return vol_fd;
2196  }
2197  }
2198 #endif /* !WINDOWS */
2199 
2200 #if !defined(CS_MODE)
2201  if (fileio_cache (vol_id, vol_label_p, vol_fd, lockf_type) != vol_fd)
2202  {
2203  /* This should not happen, the volume seems to be mounted by someone else */
2204  fileio_dismount (thread_p, vol_fd);
2205  fileio_unformat (thread_p, vol_label_p);
2206  vol_fd = NULL_VOLDES;
2207 
2208  return vol_fd;
2209  }
2210 #endif /* !CS_MODE */
2211  }
2212 
2213  er_log_debug (ARG_FILE_LINE, "Created volume %s\n", vol_label_p);
2214 
2215  return vol_fd;
2216 }
2217 
2218 /*
2219  * fileio_create_backup_volume () - CREATE A BACKUP VOLUME (INSURE ENOUGH SPACE EXISTS)
2220  * return: volume descriptor identifier on success, NULL_VOLDES on failure
2221  * db_fullname(in): Name of the database where the volume belongs
2222  * vlabel(in): Volume label
2223  * volid(in): Volume identifier
2224  * dolock(in): Lock the volume from other Unix processes
2225  * dosync(in): synchronize the writes on the volume ?
2226  * atleast_npages(in): minimum number of pages required to be free
2227  *
2228  * Note: Tests to insure that there is at least the minimum requred amount of
2229  * space on the given file system are. Then calls fileio_create to create
2230  * the volume (or file) without initializing it. This is needed for tape
2231  * backups since they are not initialized at all plus saves time w/out
2232  * formatting.
2233  * Note: Space checking does not apply to devices, only files.
2234  */
2235 static int
2236 fileio_create_backup_volume (THREAD_ENTRY * thread_p, const char *db_full_name_p, const char *vol_label_p, VOLID vol_id,
2237  bool is_do_lock, bool is_do_sync, int atleast_npages)
2238 {
2239  struct stat stbuf;
2240  int num_free;
2241 
2242  if (stat (vol_label_p, &stbuf) != -1)
2243  {
2244 #if !defined(WINDOWS)
2245  /* In WINDOWS platform, FIFO is not supported, until now. FIFO must be existent before backup operation is
2246  * executed. */
2247  if (S_ISFIFO (stbuf.st_mode))
2248  {
2249  int vdes;
2250  struct timeval to = { 0, 100000 };
2251 
2252  while (true)
2253  {
2254  vdes = fileio_open (vol_label_p, O_WRONLY | O_NONBLOCK, 0200);
2255  if (vdes != NULL_VOLDES)
2256  {
2257  break;
2258  }
2259 
2260  if (errno == ENXIO)
2261  {
2262  /* sleep for 100 milli-seconds : consider cs & sa mode */
2263  select (0, NULL, NULL, NULL, &to);
2264 
2265 #if !defined(CS_MODE)
2266  if (pgbuf_is_log_check_for_interrupts (thread_p) == true)
2267  {
2268  return NULL_VOLDES;
2269  }
2270 #endif
2271  continue;
2272  }
2274  return NULL_VOLDES;
2275  }
2276  return vdes;
2277  }
2278 #endif /* !WINDOWS */
2279  /* If there is not enough space in filesystem, then do not bother opening backup volume */
2280  if (atleast_npages > 0 && S_ISREG (stbuf.st_mode))
2281  {
2282  num_free = fileio_get_number_of_partition_free_pages (vol_label_p, IO_PAGESIZE);
2283  if (num_free < atleast_npages)
2284  {
2285  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_FORMAT_OUT_OF_SPACE, 5, vol_label_p, atleast_npages,
2286  (long long) ((IO_PAGESIZE / 1024) * atleast_npages), num_free,
2287  (long long) ((IO_PAGESIZE / 1024) * num_free));
2288  return NULL_VOLDES;
2289  }
2290  }
2291  }
2292 
2293  return (fileio_create (thread_p, db_full_name_p, vol_label_p, vol_id, is_do_lock, is_do_sync));
2294 }
2295 
2296 /*
2297  * fileio_format () - Format a volume of npages and mount the volume
2298  * return: volume descriptor identifier on success, NULL_VOLDES on failure
2299  * db_fullname(in): Name of the database where the volume belongs
2300  * vlabel(in): Volume label
2301  * volid(in): Volume identifier
2302  * npages(in): Number of pages
2303  * sweep_clean(in): Clean the newly formatted volume
2304  * dolock(in): Lock the volume from other Unix processes
2305  * dosync(in): synchronize the writes on the volume ?
2306  * kbytes_to_be_written_per_sec : size to add volume per sec
2307  *
2308  * Note: If sweep_clean is true, every page is initialized with recovery
2309  * information. In addition a volume can be optionally locked.
2310  * For example, the active log volume is locked to prevent
2311  * several server processes from accessing the same database.
2312  */
2313 int
2314 fileio_format (THREAD_ENTRY * thread_p, const char *db_full_name_p, const char *vol_label_p, VOLID vol_id,
2315  DKNPAGES npages, bool is_sweep_clean, bool is_do_lock, bool is_do_sync, size_t page_size,
2316  int kbytes_to_be_written_per_sec, bool reuse_file)
2317 {
2318  int vol_fd;
2319  FILEIO_PAGE *malloc_io_page_p;
2320  off_t offset;
2321  DKNPAGES max_npages;
2322 #if !defined(WINDOWS)
2323  struct stat buf;
2324 #endif
2325  bool is_raw_device = false;
2326 
2327  /* Check for bad number of pages...and overflow */
2328  if (npages <= 0)
2329  {
2330  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_FORMAT_BAD_NPAGES, 2, vol_label_p, npages);
2331  return NULL_VOLDES;
2332  }
2333 
2334  if (fileio_is_volume_exist (vol_label_p) == true && reuse_file == false)
2335  {
2336  /* The volume that we are trying to create already exist. Remove it and try again */
2337 #if !defined(WINDOWS)
2338  if (lstat (vol_label_p, &buf) != 0)
2339  {
2341  }
2342 
2343  if (!S_ISLNK (buf.st_mode))
2344  {
2345  fileio_unformat (thread_p, vol_label_p);
2346  }
2347  else
2348  {
2349  if (stat (vol_label_p, &buf) != 0)
2350  {
2352  }
2353 
2354  is_raw_device = S_ISCHR (buf.st_mode);
2355  }
2356 #else /* !WINDOWS */
2357  fileio_unformat (thread_p, vol_label_p);
2358  is_raw_device = false;
2359 #endif /* !WINDOWS */
2360  }
2361 
2362  if (is_raw_device)
2363  {
2364  max_npages = (DKNPAGES) VOL_MAX_NPAGES (page_size);
2365  }
2366  else
2367  {
2368  max_npages = fileio_get_number_of_partition_free_pages (vol_label_p, page_size);
2369  }
2370 
2371  offset = FILEIO_GET_FILE_SIZE (page_size, npages - 1);
2372 
2373  /*
2374  * Make sure that there is enough pages on the given partition before we
2375  * create and initialize the volume.
2376  * We should also check for overflow condition.
2377  */
2378  if (npages > max_npages || (offset < npages && npages > 1))
2379  {
2380  if (offset < npages)
2381  {
2382  /* Overflow */
2383  offset = FILEIO_GET_FILE_SIZE (page_size, VOL_MAX_NPAGES (page_size));
2384  }
2385 
2386  if (max_npages >= 0)
2387  {
2388  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_FORMAT_OUT_OF_SPACE, 5, vol_label_p, npages, (offset / 1024),
2389  max_npages, FILEIO_GET_FILE_SIZE (page_size / 1024, max_npages));
2390  }
2391  else
2392  {
2393  /* There was an error in fileio_get_number_of_partition_free_pages */
2394  ;
2395  }
2396 
2397  return NULL_VOLDES;
2398  }
2399 
2400  malloc_io_page_p = (FILEIO_PAGE *) malloc (page_size);
2401  if (malloc_io_page_p == NULL)
2402  {
2404  return NULL_VOLDES;
2405  }
2406 
2407  memset ((char *) malloc_io_page_p, 0, page_size);
2408  (void) fileio_initialize_res (thread_p, malloc_io_page_p, (PGLENGTH) page_size);
2409 
2410  vol_fd = fileio_create (thread_p, db_full_name_p, vol_label_p, vol_id, is_do_lock, is_do_sync);
2411  FI_TEST (thread_p, FI_TEST_FILE_IO_FORMAT, 0);
2412  if (vol_fd != NULL_VOLDES)
2413  {
2414  /* initialize the pages of the volume. */
2415 
2416  /* initialize at least two pages, the header page and the last page. in case of is_sweep_clean == true, every
2417  * page of the volume will be written. */
2418 
2419  if (fileio_write_or_add_to_dwb (thread_p, vol_fd, malloc_io_page_p, 0, page_size) == NULL)
2420  {
2421  fileio_dismount (thread_p, vol_fd);
2422  fileio_unformat (thread_p, vol_label_p);
2423  free_and_init (malloc_io_page_p);
2424 
2425  if (er_errid () != ER_INTERRUPTED)
2426  {
2428  }
2429 
2430  vol_fd = NULL_VOLDES;
2431  return vol_fd;
2432  }
2433 
2434 #if defined(HPUX)
2435  if ((is_sweep_clean == true
2436  && !fileio_initialize_pages (vol_fd, malloc_io_page_p, npages, page_size, kbytes_to_be_written_per_sec))
2437  || (is_sweep_clean == false
2438  && !fileio_write (vol_fd, malloc_io_page_p, npages - 1, page_size, FILEIO_WRITE_DEFAULT_WRITE)))
2439 #else /* HPUX */
2440  if (!((fileio_write_or_add_to_dwb (thread_p, vol_fd, malloc_io_page_p, npages - 1, page_size) == malloc_io_page_p)
2441  && (is_sweep_clean == false
2442  || fileio_initialize_pages (thread_p, vol_fd, malloc_io_page_p, 0, npages, page_size,
2443  kbytes_to_be_written_per_sec) == malloc_io_page_p)))
2444 #endif /* HPUX */
2445  {
2446  /* It is likely that we run of space. The partition where the volume was created has been used since we
2447  * checked above. */
2448 
2449  max_npages = fileio_get_number_of_partition_free_pages (vol_label_p, page_size);
2450 
2451  fileio_dismount (thread_p, vol_fd);
2452  fileio_unformat (thread_p, vol_label_p);
2453  free_and_init (malloc_io_page_p);
2454  if (er_errid () != ER_INTERRUPTED)
2455  {
2457  (offset / 1024), max_npages, (long long) ((page_size / 1024) * max_npages));
2458  }
2459  vol_fd = NULL_VOLDES;
2460  return vol_fd;
2461  }
2462 
2463 #if defined(WINDOWS)
2464  fileio_dismount (thread_p, vol_fd);
2465  vol_fd = fileio_mount (thread_p, NULL, vol_label_p, vol_id, false, false);
2466 #endif /* WINDOWS */
2467  }
2468  else
2469  {
2470  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_CREATE_VOL, 2, vol_label_p, db_full_name_p);
2471  }
2472 
2473  free_and_init (malloc_io_page_p);
2474  return vol_fd;
2475 }
2476 
2477 #if !defined (CS_MODE)
2478 /*
2479  * fileio_expand_to () - Expand a volume to the given number of pages.
2480  *
2481  * return:
2482  *
2483  * error code or NO_ERROR
2484  *
2485  *
2486  * arguments:
2487  *
2488  * vol_id : Volume identifier
2489  * size_npages : New size in pages
2490  * voltype : temporary or permanent volume type
2491  *
2492  *
2493  * How it works:
2494  *
2495  * A new size for file is provided. The new size is expected to be bigger than current size (with the exception of
2496  * recovery cases). This approach replaced extending by a given size to fix recovery errors (file extension could
2497  * be executed twice).
2498  *
2499  * Enough disk space is checked first before doing extend.
2500  *
2501  * Notes:
2502  *
2503  * Pages are not sweep_clean/initialized if they are part of temporary volumes.
2504  *
2505  * No checking for temporary volumes is performed by this function.
2506  *
2507  * On WINDOWS && SERVER MODE io_mutex lock must be obtained before calling lseek. Otherwise, expanding can
2508  * interfere with fileio_read and fileio_write calls. This caused corruptions in the temporary file, random pages
2509  * being written at the end of file instead of being written at their designated places.
2510  */
2511 int
2512 fileio_expand_to (THREAD_ENTRY * thread_p, VOLID vol_id, DKNPAGES size_npages, DB_VOLTYPE voltype)
2513 {
2514  int vol_fd;
2515  const char *vol_label_p;
2516  FILEIO_PAGE *io_page_p;
2517  DKNPAGES max_npages;
2518  size_t max_size;
2519  PAGEID start_pageid;
2520  size_t current_size;
2521  PAGEID last_pageid;
2522  size_t new_size;
2523  size_t desired_extend_size;
2524  size_t max_extend_size;
2525 #if defined(WINDOWS) && defined(SERVER_MODE)
2526  int rv;
2527  pthread_mutex_t *io_mutex;
2528  static pthread_mutex_t io_mutex_instance = PTHREAD_MUTEX_INITIALIZER;
2529 #endif /* WINDOWS && SERVER_MODE */
2530 
2531  int error_code = NO_ERROR;
2532 
2533  assert (size_npages > 0);
2534 
2535  vol_fd = fileio_get_volume_descriptor (vol_id);
2536  vol_label_p = fileio_get_volume_label (vol_id, PEEK);
2537 
2538  if (vol_fd == NULL_VOLDES || vol_label_p == NULL)
2539  {
2540  assert (false); /* I don't think we can accept this case */
2541  return ER_FAILED;
2542  }
2543 
2544  max_npages = fileio_get_number_of_partition_free_pages (vol_label_p, IO_PAGESIZE);
2545  if (max_npages < 0)
2546  {
2547  ASSERT_ERROR_AND_SET (error_code);
2548  return error_code;
2549  }
2550 
2551 #if defined(WINDOWS) && defined(SERVER_MODE)
2552  io_mutex = fileio_get_volume_mutex (thread_p, vol_fd);
2553  if (io_mutex == NULL)
2554  {
2555  io_mutex = &io_mutex_instance;
2556  }
2557 
2558  rv = pthread_mutex_lock (io_mutex);
2559  if (rv != 0)
2560  {
2562  return ER_FAILED;
2563  }
2564 #endif /* WINDOWS && SERVER_MODE */
2565 
2566  /* get current size */
2567  current_size = lseek (vol_fd, 0, SEEK_END);
2568 #if defined(WINDOWS) && defined(SERVER_MODE)
2569  pthread_mutex_unlock (io_mutex);
2570 #endif /* WINDOWS && SERVER_MODE */
2571  /* safe-guard: current size is rounded to IO_PAGESIZE... unless it crashed during an expand */
2572  assert (!LOG_ISRESTARTED () || (current_size % IO_PAGESIZE) == 0);
2573 
2574  /* compute new size */
2575  new_size = ((size_t) size_npages) * IO_PAGESIZE;
2576 
2577  if (new_size <= current_size)
2578  {
2579  /* this is possible in limited cases. we cannot link file expand to a page, so sometimes we may expand but volume
2580  * header does not reflect this change. also, once expanded, we don't undo the expansion.
2581  * however next time volume wants to expand (this case), it just notices file is already expanded and all is
2582  * good. */
2583  er_log_debug (ARG_FILE_LINE, "skip extending volume %d with current size %zu to new size %zu\n",
2584  vol_id, current_size, new_size);
2585  return NO_ERROR;
2586  }
2587 
2588  /* overflow safety check */
2589  /* is this necessary? we dropped support for 32-bits systems. for now, I'll leave this check */
2590  max_size = ((size_t) VOL_MAX_NPAGES (IO_PAGESIZE)) * IO_PAGESIZE;
2591  new_size = MIN (new_size, max_size);
2592 
2593  /* consider disk free space */
2594  desired_extend_size = new_size - current_size;
2595  max_extend_size = ((size_t) max_npages) * IO_PAGESIZE;
2596 
2597  if (max_extend_size < desired_extend_size)
2598  {
2599  const size_t ONE_KILO = 1024;
2600  error_code = ER_IO_EXPAND_OUT_OF_SPACE;
2601 
2603  desired_extend_size / IO_PAGESIZE, new_size / ONE_KILO, max_npages,
2604  FILEIO_GET_FILE_SIZE (IO_PAGESIZE / ONE_KILO, max_npages));
2605  }
2606 
2607  /* init page */
2608  io_page_p = (FILEIO_PAGE *) db_private_alloc (thread_p, IO_PAGESIZE);
2609  if (io_page_p == NULL)
2610  {
2611  /* TBD: remove memory allocation manual checks. */
2612  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) IO_PAGESIZE);
2613  return ER_OUT_OF_VIRTUAL_MEMORY;
2614  }
2615 
2616  memset (io_page_p, 0, IO_PAGESIZE);
2617  (void) fileio_initialize_res (thread_p, io_page_p, IO_PAGESIZE);
2618 
2619  start_pageid = (PAGEID) (current_size / IO_PAGESIZE);
2620  last_pageid = ((PAGEID) (new_size / IO_PAGESIZE) - 1);
2621 
2622  if (voltype == DB_TEMPORARY_VOLTYPE)
2623  {
2624  /* Write the last page */
2625  if (fileio_write_or_add_to_dwb (thread_p, vol_fd, io_page_p, last_pageid, IO_PAGESIZE) != io_page_p)
2626  {
2627  ASSERT_ERROR_AND_SET (error_code);
2628  }
2629  }
2630  else
2631  {
2632  /* support generic volume only */
2633  assert_release (voltype == DB_PERMANENT_VOLTYPE);
2634 
2635  if (fileio_initialize_pages (thread_p, vol_fd, io_page_p, start_pageid, last_pageid - start_pageid + 1,
2636  IO_PAGESIZE, -1) == NULL)
2637  {
2638  ASSERT_ERROR_AND_SET (error_code);
2639  }
2640  }
2641 
2642  if (error_code != NO_ERROR && error_code != ER_INTERRUPTED)
2643  {
2644  /* I don't like below assumption, it can be misleading. From what I have seen, errors are already set. */
2645 #if 0
2646  /* It is likely that we run of space. The partition where the volume was created has been used since we checked
2647  * above.
2648  */
2649  max_npages = fileio_get_number_of_partition_free_pages (vol_label_p, IO_PAGESIZE);
2650  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_EXPAND_OUT_OF_SPACE, 5, vol_label_p, size_npages,
2651  last_offset / 1024, max_npages, FILEIO_GET_FILE_SIZE (IO_PAGESIZE / 1024, max_npages));
2652 #endif /* 0 */
2653  }
2654 
2655  db_private_free (thread_p, io_page_p);
2656 
2657  return error_code;
2658 }
2659 #endif /* not CS_MODE */
2660 
2661 #if defined(ENABLE_UNUSED_FUNCTION)
2662 /*
2663  * fileio_truncate () - TRUNCATE A TEMPORARY VOLUME
2664  * return: npages
2665  * volid(in): Volume identifier
2666  * npages_to_resize(in): Number of pages to resize
2667  */
2668 DKNPAGES
2669 fileio_truncate (VOLID vol_id, DKNPAGES npages_to_resize)
2670 {
2671  int vol_fd;
2672  const char *vol_label_p;
2673  off_t length;
2674  bool is_retry = true;
2675 
2676  vol_fd = fileio_get_volume_descriptor (vol_id);
2677  vol_label_p = fileio_get_volume_label (vol_id, PEEK);
2678 
2679  if (vol_fd == NULL_VOLDES || vol_label_p == NULL)
2680  {
2681  return -1;
2682  }
2683 
2684  if (npages_to_resize <= 0)
2685  {
2686  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_FORMAT_BAD_NPAGES, 2, vol_label_p, npages_to_resize);
2687  return -1;
2688  }
2689 
2690  length = FILEIO_GET_FILE_SIZE (IO_PAGESIZE, npages_to_resize);
2691  while (is_retry == true)
2692  {
2693  is_retry = false;
2694  if (ftruncate (vol_fd, length))
2695  {
2696  if (errno == EINTR)
2697  {
2698  is_retry = true;
2699  }
2700  else
2701  {
2704  return -1;
2705  }
2706  }
2707  }
2708  return npages_to_resize;
2709 }
2710 #endif
2711 
2712 /*
2713  * fileio_unformat () - DESTROY A VOLUME
2714  * return: void
2715  * vlabel(in): Label of volume to unformat
2716  *
2717  * Note: If the volume is mounted, it is dismounted. Then, the volume is
2718  * destroyed/unformatted.
2719  */
2720 void
2721 fileio_unformat (THREAD_ENTRY * thread_p, const char *vol_label_p)
2722 {
2723  fileio_unformat_and_rename (thread_p, vol_label_p, NULL);
2724 }
2725 
2726 /*
2727  * fileio_unformat_and_rename () - DESTROY A VOLUME
2728  * return: void
2729  * vol_label(in): Label of volume to unformat
2730  * new_vlabel(in): New volume label. if NULL, volume will be deleted
2731  *
2732  * Note: If the volume is mounted, it is dismounted. Then, the volume is
2733  * destroyed/unformatted.
2734  */
2735 void
2736 fileio_unformat_and_rename (THREAD_ENTRY * thread_p, const char *vol_label_p, const char *new_label_p)
2737 {
2738 #if defined (EnableThreadMonitoring)
2739  TSC_TICKS start_tick, end_tick;
2740  TSCTIMEVAL elapsed_time;
2741 #endif
2742 #if !defined(CS_MODE)
2743  int vol_fd;
2744  char vlabel_p[PATH_MAX];
2745 
2746  /* Dismount the volume if it is mounted */
2747  vol_fd = fileio_find_volume_descriptor_with_label (vol_label_p);
2748  if (vol_fd != NULL_VOLDES)
2749  {
2750  /* if vol_label_p is a pointer of global vinfo->vlabel, It can be reset in fileio_dismount */
2751  strcpy (vlabel_p, vol_label_p);
2752  vol_label_p = vlabel_p;
2753  fileio_dismount (thread_p, vol_fd);
2754  }
2755 #endif /* !CS_MODE */
2756 
2757 #if defined (EnableThreadMonitoring)
2759  {
2760  tsc_getticks (&start_tick);
2761  }
2762 #endif
2763 
2764  if (new_label_p == NULL)
2765  {
2766  (void) remove (vol_label_p);
2767  }
2768  else
2769  {
2770  if (os_rename_file (vol_label_p, new_label_p) != NO_ERROR)
2771  {
2772  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_RENAME_FAIL, 2, vol_label_p, new_label_p);
2773  }
2774  }
2775 
2776 #if defined (EnableThreadMonitoring)
2778  {
2779  tsc_getticks (&end_tick);
2780  tsc_elapsed_time_usec (&elapsed_time, end_tick, start_tick);
2781  }
2782 
2783  if (MONITOR_WAITING_THREAD (elapsed_time))
2784  {
2787  er_log_debug (ARG_FILE_LINE, "fileio_unformat: %6d.%06d\n", elapsed_time.tv_sec, elapsed_time.tv_usec);
2788  }
2789 #endif
2790 
2791  er_log_debug (ARG_FILE_LINE, "Destroyed volume %s\n", vol_label_p);
2792 }
2793 
2794 /*
2795  * fileio_copy_volume () - COPY A DISK
2796  * return: volume descriptor identifier on success, NULL_VOLDES on failure
2797  * from_vdes(in): From Volume descriptor
2798  * npages(in): From Volume descriptor
2799  * to_vlabel(in): To Volume label
2800  * to_volid(in): Volume identifier assigned to the copy
2801  * reset_rcvinfo(in): Reset recovery information?
2802  *
2803  * Note: Format a new volume with the number of given pages and copy
2804  * the contents of the volume associated with from_vdes onto the
2805  * new generated volume. The recovery information kept in every
2806  * page may be optionally initialized.
2807  */
2808 int
2809 fileio_copy_volume (THREAD_ENTRY * thread_p, int from_vol_desc, DKNPAGES npages, const char *to_vol_label_p,
2810  VOLID to_vol_id, bool is_reset_recovery_info)
2811 {
2812  PAGEID page_id;
2813  FILEIO_PAGE *malloc_io_page_p = NULL;
2814  int to_vol_desc;
2815 
2816  /*
2817  * Create the to_volume. Don't initialize the volume with recovery
2818  * information since it generated/created when the content of the pages are
2819  * copied.
2820  */
2821 
2822 #if defined(HPUX)
2823  /* HP-UX shows the poor performance in fileio_format(). */
2824  to_vol_desc = fileio_create (NULL, to_vol_label_p, to_vol_id, false, false);
2825 #else /* HPUX */
2826  to_vol_desc =
2827  fileio_format (thread_p, NULL, to_vol_label_p, to_vol_id, npages, false, false, false, IO_PAGESIZE, 0, false);
2828 #endif /* HPUX */
2829  if (to_vol_desc == NULL_VOLDES)
2830  {
2831  return NULL_VOLDES;
2832  }
2833 
2834  /* Don't read the pages from the page buffer pool but directly from disk */
2835  malloc_io_page_p = (FILEIO_PAGE *) malloc (IO_PAGESIZE);
2836  if (malloc_io_page_p == NULL)
2837  {
2839  goto error;
2840  }
2841 
2842  if (is_reset_recovery_info == false)
2843  {
2844  /* Copy the volume as it is */
2845  for (page_id = 0; page_id < npages; page_id++)
2846  {
2847  if (fileio_read (thread_p, from_vol_desc, malloc_io_page_p, page_id, IO_PAGESIZE) == NULL
2848  || fileio_write_or_add_to_dwb (thread_p, to_vol_desc, malloc_io_page_p, page_id, IO_PAGESIZE) == NULL)
2849  {
2850  goto error;
2851  }
2852  }
2853  }
2854  else
2855  {
2856  /* Reset the recovery information. Just like if this was a formatted volume */
2857  for (page_id = 0; page_id < npages; page_id++)
2858  {
2859  if (fileio_read (thread_p, from_vol_desc, malloc_io_page_p, page_id, IO_PAGESIZE) == NULL)
2860  {
2861  goto error;
2862  }
2863  else
2864  {
2865  fileio_reset_page_lsa (malloc_io_page_p, IO_PAGESIZE);
2866  if (fileio_write_or_add_to_dwb (thread_p, to_vol_desc, malloc_io_page_p, page_id, IO_PAGESIZE) == NULL)
2867  {
2868  goto error;
2869  }
2870  }
2871  }
2872  }
2873 
2874  if (fileio_synchronize (thread_p, to_vol_desc, to_vol_label_p, FILEIO_SYNC_ALSO_FLUSH_DWB) != to_vol_desc)
2875  {
2876  goto error;
2877  }
2878 
2879  free_and_init (malloc_io_page_p);
2880  return to_vol_desc;
2881 
2882 error:
2883  fileio_dismount (thread_p, to_vol_desc);
2884  fileio_unformat (thread_p, to_vol_label_p);
2885  if (malloc_io_page_p != NULL)
2886  {
2887  free_and_init (malloc_io_page_p);
2888  }
2889 
2890  return NULL_VOLDES;
2891 }
2892 
2893 /*
2894  * fileio_reset_volume () - Reset the recovery information (LSA) of all pages of given
2895  * volume with given reset_lsa
2896  * return:
2897  * vdes(in): Volume descriptor
2898  * vlabel(in): Volume label
2899  * npages(in): Number of pages of volume to reset
2900  * reset_lsa(in): The reset recovery information LSA
2901  */
2902 int
2903 fileio_reset_volume (THREAD_ENTRY * thread_p, int vol_fd, const char *vlabel, DKNPAGES npages,
2904  const LOG_LSA * reset_lsa_p)
2905 {
2906  PAGEID page_id;
2907  FILEIO_PAGE *malloc_io_page_p;
2908  int success = NO_ERROR;
2909  bool skip_flush = false;
2910 
2911  malloc_io_page_p = (FILEIO_PAGE *) malloc (IO_PAGESIZE);
2912  if (malloc_io_page_p == NULL)
2913  {
2915  return ER_FAILED;
2916  }
2917 
2918  for (page_id = 0; page_id < npages; page_id++)
2919  {
2920  if (fileio_read (thread_p, vol_fd, malloc_io_page_p, page_id, IO_PAGESIZE) != NULL)
2921  {
2922  fileio_set_page_lsa (malloc_io_page_p, reset_lsa_p, IO_PAGESIZE);
2923 
2924  if (fileio_write_or_add_to_dwb (thread_p, vol_fd, malloc_io_page_p, page_id, IO_PAGESIZE) == NULL)
2925  {
2926  success = ER_FAILED;
2927  break;
2928  }
2929  }
2930  else
2931  {
2932  success = ER_FAILED;
2933  break;
2934  }
2935  }
2936  free_and_init (malloc_io_page_p);
2937 
2938  if (fileio_synchronize (thread_p, vol_fd, vlabel, FILEIO_SYNC_ALSO_FLUSH_DWB) != vol_fd)
2939  {
2940  success = ER_FAILED;
2941  }
2942 
2943  return success;
2944 }
2945 
2946 /*
2947  * fileio_mount () - Mount the volume associated with the given name and permanent
2948  * identifier
2949  * return: volume descriptor identifier on success, NULL_VOLDES on failure
2950  * db_fullname(in): Name of the database where the volume belongs
2951  * vlabel(in): Volume label
2952  * volid(in): Permanent Volume identifier
2953  * lockwait(in): Lock the volume from other Unix processes
2954  * dosync(in): synchronize the writes on the volume ?
2955  */
2956 int
2957 fileio_mount (THREAD_ENTRY * thread_p, const char *db_full_name_p, const char *vol_label_p, VOLID vol_id, int lock_wait,
2958  bool is_do_sync)
2959 {
2960 #if defined(WINDOWS)
2961  int vol_fd;
2962  int sh_flags;
2963 
2964 #if !defined(CS_MODE)
2966 
2967  /* Is volume already mounted ? */
2968  vol_fd = fileio_find_volume_descriptor_with_label (vol_label_p);
2969  if (vol_fd != NULL_VOLDES)
2970  {
2971  return vol_fd;
2972  }
2973 #endif /* !CS_MODE */
2974 
2975  sh_flags = lock_wait > 0 ? _SH_DENYWR : _SH_DENYNO;
2976 
2977  vol_fd = _sopen (vol_label_p, _O_RDWR | _O_BINARY, sh_flags, 0600);
2978  if (vol_fd == NULL_VOLDES)
2979  {
2980  if (sh_flags == _SH_DENYWR && errno != ENOENT)
2981  {
2982  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_MOUNT_LOCKED, 6, vol_label_p, db_full_name_p,
2983  "-", 0, "-", "-");
2984  }
2985  else
2986  {
2988  }
2989  return NULL_VOLDES;
2990  }
2991 
2992 #if !defined(CS_MODE)
2993  /* Cache mounting information */
2994  if (fileio_cache (vol_id, vol_label_p, vol_fd, FILEIO_NOT_LOCKF) != vol_fd)
2995  {
2996  fileio_dismount (thread_p, vol_fd);
2997  return NULL_VOLDES;
2998  }
2999 #endif /* !CS_MODE */
3000 
3001  return vol_fd;
3002 
3003 #else /* WINDOWS */
3004  int vol_fd;
3005  int o_sync;
3006  FILEIO_LOCKF_TYPE lockf_type = FILEIO_NOT_LOCKF;
3007  bool is_do_wait;
3008  struct stat stat_buf;
3009  time_t last_modification_time = 0;
3010  off_t last_size = 0;
3011 
3012 #if !defined(CS_MODE)
3014 
3015  /* Is volume already mounted ? */
3016  vol_fd = fileio_find_volume_descriptor_with_label (vol_label_p);
3017  if (vol_fd != NULL_VOLDES)
3018  {
3019  return vol_fd;
3020  }
3021 #endif /* !CS_MODE */
3022 
3023  o_sync = (is_do_sync != false) ? O_SYNC : 0;
3024 
3025  /* OPEN THE DISK VOLUME PARTITION OR FILE SIMULATED VOLUME */
3026 start:
3027  vol_fd = fileio_open (vol_label_p, O_RDWR | o_sync, 0600);
3028  if (vol_fd == NULL_VOLDES)
3029  {
3031  return NULL_VOLDES;
3032  }
3033 
3034  is_do_wait = (lock_wait > 1) ? true : false;
3035  if (is_do_wait)
3036  {
3037  if (fstat (vol_fd, &stat_buf) != 0)
3038  {
3039  fileio_close (vol_fd);
3040  return NULL_VOLDES;
3041  }
3042  last_modification_time = stat_buf.st_mtime;
3043  last_size = stat_buf.st_size;
3044  }
3045 
3046 #if _POSIX_C_SOURCE >= 200112L
3048  {
3049  int advise_flag = 0;
3050  off_t amount = 0; /* entire volume */
3052  {
3053  case 1:
3054  advise_flag = POSIX_FADV_NORMAL;
3055  break;
3056  case 2:
3057  advise_flag = POSIX_FADV_SEQUENTIAL;
3058  break;
3059  case 3:
3060  advise_flag = POSIX_FADV_RANDOM;
3061  break;
3062  case 4:
3063  advise_flag = POSIX_FADV_NOREUSE;
3064  break;
3065  case 5:
3066  advise_flag = POSIX_FADV_WILLNEED;
3067  break;
3068  case 6:
3069  advise_flag = POSIX_FADV_DONTNEED;
3070  break;
3071  }
3072 
3073  if (posix_fadvise (vol_fd, 0, amount, advise_flag) != 0)
3074  {
3076  return NULL_VOLDES;
3077  }
3078  }
3079 #endif /* _POSIX_C_SOURCE >= 200112L */
3080 
3081  /* LOCK THE DISK */
3082  if (lock_wait != 0)
3083  {
3084  lockf_type = fileio_lock (db_full_name_p, vol_label_p, vol_fd, is_do_wait);
3085  if (lockf_type == FILEIO_NOT_LOCKF)
3086  {
3087  /* Volume seems to be mounted by someone else */
3088  fileio_close (vol_fd);
3089  return NULL_VOLDES;
3090  }
3091  else if (lockf_type == FILEIO_LOCKF && is_do_wait == true)
3092  {
3093  /* may need to reopen the file */
3094  if (fstat (vol_fd, &stat_buf) != 0)
3095  {
3096  fileio_dismount (thread_p, vol_fd);
3097  return NULL_VOLDES;
3098  }
3099 
3100  if (last_modification_time != stat_buf.st_mtime || last_size != stat_buf.st_size)
3101  {
3102  /* somebody changed the file before the file lock was acquired */
3103  fileio_dismount (thread_p, vol_fd);
3104  goto start;
3105  }
3106  }
3107  }
3108 
3109 #if !defined(CS_MODE)
3110  /* Cache mounting information */
3111  if (fileio_cache (vol_id, vol_label_p, vol_fd, lockf_type) != vol_fd)
3112  {
3113  fileio_dismount (thread_p, vol_fd);
3114  return NULL_VOLDES;
3115  }
3116 #endif /* !CS_MODE */
3117 
3118  if (prm_get_bool_value (PRM_ID_DBFILES_PROTECT) == true && vol_fd > 0)
3119  {
3120  fileio_set_permission (vol_label_p);
3121  }
3122 
3123  return vol_fd;
3124 #endif /* WINDOWS */
3125 }
3126 
3127 /*
3128  * fileio_dismount () - Dismount the volume associated with the given volume
3129  * descriptor
3130  * return: void
3131  * vdes(in): Volume descriptor
3132  */
3133 void
3134 fileio_dismount (THREAD_ENTRY * thread_p, int vol_fd)
3135 {
3136  const char *vlabel;
3137 #if !defined(WINDOWS)
3138  FILEIO_LOCKF_TYPE lockf_type;
3139 #endif /* !WINDOWS */
3140  /*
3141  * Make sure that all dirty pages of the volume are forced to disk. This
3142  * is needed since a close of a file and program exist, does not imply
3143  * that the dirty pages of the file (or files that the program opened) are
3144  * forced to disk.
3145  */
3146  vlabel = fileio_get_volume_label_by_fd (vol_fd, PEEK);
3147 
3148  (void) fileio_synchronize (thread_p, vol_fd, vlabel, FILEIO_SYNC_ALSO_FLUSH_DWB);
3149 
3150 #if !defined(WINDOWS)
3151  lockf_type = fileio_get_lockf_type (vol_fd);
3152  if (lockf_type != FILEIO_NOT_LOCKF)
3153  {
3154  fileio_unlock (vlabel, vol_fd, lockf_type);
3155  }
3156 #endif /* !WINDOWS */
3157 
3158  fileio_close (vol_fd);
3159 
3160  /* Decache volume information even during errors */
3161  fileio_decache (thread_p, vol_fd);
3162 }
3163 
3164 /*
3165  * fileio_dismount_without_fsync () -
3166  * return:
3167  * vdes(in):
3168  */
3169 void
3171 {
3172 #if !defined (WINDOWS)
3173  FILEIO_LOCKF_TYPE lockf_type;
3174 
3175  lockf_type = fileio_get_lockf_type (vol_fd);
3176  if (lockf_type != FILEIO_NOT_LOCKF)
3177  {
3178  fileio_unlock (fileio_get_volume_label_by_fd (vol_fd, PEEK), vol_fd, lockf_type);
3179  }
3180 #endif /* !WINDOWS */
3181 
3182  fileio_close (vol_fd);
3183 
3184  /* Decache volume information even during errors */
3185  fileio_decache (thread_p, vol_fd);
3186 }
3187 
3188 static int
3189 fileio_max_permanent_volumes (int index, int num_permanent_volums)
3190 {
3191  if (index < (num_permanent_volums - 1) / FILEIO_VOLINFO_INCREMENT)
3192  {
3193  return FILEIO_VOLINFO_INCREMENT - 1;
3194  }
3195  else
3196  {
3197  return (num_permanent_volums - 1) % FILEIO_VOLINFO_INCREMENT;
3198  }
3199 }
3200 
3201 static int
3202 fileio_min_temporary_volumes (int index, int num_temp_volums, int num_volinfo_array)
3203 {
3204  if (index > (num_volinfo_array - 1 - (num_temp_volums - 1) / FILEIO_VOLINFO_INCREMENT))
3205  {
3206  return 0;
3207  }
3208  else
3209  {
3210  return FILEIO_VOLINFO_INCREMENT - 1 - (num_temp_volums - 1) % FILEIO_VOLINFO_INCREMENT;
3211  }
3212 }
3213 
3216 {
3217  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
3218  int rv;
3219 
3220  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
3221 
3222  for (sys_vol_info_p = &fileio_Sys_vol_info_header.anchor;
3223  sys_vol_info_p != NULL && sys_vol_info_p->vdes != NULL_VOLDES; sys_vol_info_p = sys_vol_info_p->next)
3224  {
3225  if ((*apply_function) (thread_p, sys_vol_info_p, arg) == true)
3226  {
3227  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
3228  return sys_vol_info_p;
3229  }
3230  }
3231  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
3232 
3233  return NULL;
3234 }
3235 
3236 static FILEIO_VOLUME_INFO *
3238 {
3239  int i, j, max_j;
3240  FILEIO_VOLUME_HEADER *header_p;
3241  FILEIO_VOLUME_INFO *vol_info_p;
3242 
3243  header_p = &fileio_Vol_info_header;
3244 
3245  for (i = 0; i <= (header_p->next_perm_volid - 1) / FILEIO_VOLINFO_INCREMENT; i++)
3246  {
3247  max_j = fileio_max_permanent_volumes (i, header_p->next_perm_volid);
3248 
3249  for (j = 0; j <= max_j; j++)
3250  {
3251  vol_info_p = &header_p->volinfo[i][j];
3252  if ((*apply_function) (thread_p, vol_info_p, arg) == true)
3253  {
3254  return vol_info_p;
3255  }
3256  }
3257  }
3258 
3259  return NULL;
3260 }
3261 
3262 static FILEIO_VOLUME_INFO *
3264 {
3265  int i, j, max_j;
3266  FILEIO_VOLUME_HEADER *header_p;
3267  FILEIO_VOLUME_INFO *vol_info_p;
3268 
3269  header_p = &fileio_Vol_info_header;
3270 
3271  for (i = (header_p->next_perm_volid - 1) / FILEIO_VOLINFO_INCREMENT; i >= 0; i--)
3272  {
3273  max_j = fileio_max_permanent_volumes (i, header_p->next_perm_volid);
3274 
3275  for (j = max_j; j >= 0; j--)
3276  {
3277  vol_info_p = &header_p->volinfo[i][j];
3278  if ((*apply_function) (thread_p, vol_info_p, arg) == true)
3279  {
3280  return vol_info_p;
3281  }
3282  }
3283  }
3284 
3285  return NULL;
3286 }
3287 
3288 static FILEIO_VOLUME_INFO *
3290 {
3291  int i, j, min_j, num_temp_vols;
3292  FILEIO_VOLUME_HEADER *header_p;
3293  FILEIO_VOLUME_INFO *vol_info_p;
3294 
3295  header_p = &fileio_Vol_info_header;
3296  num_temp_vols = LOG_MAX_DBVOLID - header_p->next_temp_volid;
3297 
3298  for (i = header_p->num_volinfo_array - 1;
3299  i > (header_p->num_volinfo_array - 1
3300  - (num_temp_vols + FILEIO_VOLINFO_INCREMENT - 1) / FILEIO_VOLINFO_INCREMENT); i--)
3301  {
3302  min_j = fileio_min_temporary_volumes (i, num_temp_vols, header_p->num_volinfo_array);
3303 
3304  for (j = FILEIO_VOLINFO_INCREMENT - 1; j >= min_j; j--)
3305  {
3306  vol_info_p = &header_p->volinfo[i][j];
3307  if ((*apply_function) (thread_p, vol_info_p, arg) == true)
3308  {
3309  return vol_info_p;
3310  }
3311  }
3312  }
3313 
3314  return NULL;
3315 }
3316 
3317 static FILEIO_VOLUME_INFO *
3319 {
3320  int i, j, min_j, num_temp_vols;
3321  FILEIO_VOLUME_HEADER *header_p;
3322  FILEIO_VOLUME_INFO *vol_info_p;
3323 
3324  header_p = &fileio_Vol_info_header;
3325  num_temp_vols = (LOG_MAX_DBVOLID) - header_p->next_temp_volid;
3326 
3327  for (i = (header_p->num_volinfo_array - ((num_temp_vols + FILEIO_VOLINFO_INCREMENT - 1) / FILEIO_VOLINFO_INCREMENT));
3328  i < header_p->num_volinfo_array; i++)
3329  {
3330  min_j = fileio_min_temporary_volumes (i, num_temp_vols, header_p->num_volinfo_array);
3331 
3332  for (j = min_j; j < FILEIO_VOLINFO_INCREMENT; j++)
3333  {
3334  vol_info_p = &header_p->volinfo[i][j];
3335  if ((*apply_function) (thread_p, vol_info_p, arg) == true)
3336  {
3337  return vol_info_p;
3338  }
3339  }
3340  }
3341 
3342  return NULL;
3343 }
3344 
3345 static bool
3346 fileio_dismount_volume (THREAD_ENTRY * thread_p, FILEIO_VOLUME_INFO * vol_info_p, APPLY_ARG * ignore_arg)
3347 {
3348  if (vol_info_p->vdes != NULL_VOLDES)
3349  {
3350  (void) fileio_synchronize (thread_p, vol_info_p->vdes, vol_info_p->vlabel, FILEIO_SYNC_ALSO_FLUSH_DWB);
3351 
3352 #if !defined(WINDOWS)
3353  if (vol_info_p->lockf_type != FILEIO_NOT_LOCKF)
3354  {
3355  fileio_unlock (vol_info_p->vlabel, vol_info_p->vdes, vol_info_p->lockf_type);
3356  }
3357 #endif /* !WINDOWS */
3358 
3359  fileio_close (vol_info_p->vdes);
3360  }
3361 
3362 #if defined(WINDOWS) && defined(SERVER_MODE)
3363  pthread_mutex_destroy (&vol_info_p->vol_mutex);
3364 #endif /* WINDOWS && SERVER_MODE */
3365 
3366  return false;
3367 }
3368 
3369 /*
3370  * fileio_dismount_all () - Dismount all mounted volumes
3371  * return: void
3372  */
3373 void
3375 {
3376  FILEIO_SYSTEM_VOLUME_HEADER *sys_header_p;
3377  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p, *tmp_sys_vol_info_p;
3378  FILEIO_VOLUME_HEADER *vol_header_p;
3379  int i, num_perm_vols, num_temp_vols;
3380  int rv;
3381  APPLY_ARG ignore_arg = { 0 };
3382 
3383  /* First, traverse sys volumes */
3384  sys_header_p = &fileio_Sys_vol_info_header;
3385  rv = pthread_mutex_lock (&sys_header_p->mutex);
3386 
3387  for (sys_vol_info_p = &sys_header_p->anchor; sys_vol_info_p != NULL;)
3388  {
3389  if (sys_vol_info_p->vdes != NULL_VOLDES)
3390  {
3391  /* System volume. No need to sync DWB. */
3392  (void) fileio_synchronize (thread_p, sys_vol_info_p->vdes, sys_vol_info_p->vlabel, FILEIO_SYNC_ONLY);
3393 
3394 #if !defined(WINDOWS)
3395  if (sys_vol_info_p->lockf_type != FILEIO_NOT_LOCKF)
3396  {
3397  fileio_unlock (sys_vol_info_p->vlabel, sys_vol_info_p->vdes, sys_vol_info_p->lockf_type);
3398  }
3399 #endif /* !WINDOWS */
3400 
3401  fileio_close (sys_vol_info_p->vdes);
3402  }
3403 
3404  tmp_sys_vol_info_p = sys_vol_info_p;
3405  sys_vol_info_p = sys_vol_info_p->next;
3406  if (tmp_sys_vol_info_p != &sys_header_p->anchor)
3407  {
3408 #if defined(SERVER_MODE) && defined(WINDOWS)
3409  pthread_mutex_destroy (&tmp_sys_vol_info_p->sysvol_mutex);
3410 
3411 #endif /* WINDOWS */
3412  free_and_init (tmp_sys_vol_info_p);
3413  }
3414  }
3415 
3416  pthread_mutex_unlock (&sys_header_p->mutex);
3417 
3418  /* Second, traverse perm/temp volumes */
3419  vol_header_p = &fileio_Vol_info_header;
3420  rv = pthread_mutex_lock (&vol_header_p->mutex);
3421  num_perm_vols = vol_header_p->next_perm_volid;
3422 
3423  (void) fileio_traverse_permanent_volume (thread_p, fileio_dismount_volume, &ignore_arg);
3424 
3425  vol_header_p->max_perm_vols = 0;
3426  vol_header_p->next_perm_volid = 0;
3427 
3428  num_temp_vols = LOG_MAX_DBVOLID - vol_header_p->next_temp_volid;
3429 
3430  (void) fileio_traverse_temporary_volume (thread_p, fileio_dismount_volume, &ignore_arg);
3431 
3432  vol_header_p->max_temp_vols = 0;
3433  vol_header_p->next_temp_volid = LOG_MAX_DBVOLID;
3434 
3435  if (vol_header_p->volinfo != NULL)
3436  {
3437  for (i = 0; i <= (VOLID_MAX - 1) / FILEIO_VOLINFO_INCREMENT; i++)
3438  {
3439  if (vol_header_p->volinfo[i] != NULL)
3440  {
3441  free_and_init (vol_header_p->volinfo[i]);
3442  }
3443 
3444  }
3445  }
3446 
3447  free_and_init (vol_header_p->volinfo);
3448 
3449  pthread_mutex_unlock (&vol_header_p->mutex);
3450 }
3451 
3452 /*
3453  * fileio_map_mounted () - Map over the data volumes
3454  * return:
3455  * fun(in): Function to call on volid and args
3456  * args(in): argumemts for fun
3457  *
3458  * Note : Map over all data volumes (i.e., the log volumes are skipped),
3459  * by calling the given function on every volume. If the function
3460  * returns false the mapping is stopped.
3461  */
3462 bool
3463 fileio_map_mounted (THREAD_ENTRY * thread_p, bool (*fun) (THREAD_ENTRY * thread_p, VOLID vol_id, void *args),
3464  void *args)
3465 {
3466  FILEIO_VOLUME_INFO *vol_info_p;
3467  FILEIO_VOLUME_HEADER *header_p;
3468  int i, j, max_j, min_j, num_temp_vols;
3469 
3471 
3472  header_p = &fileio_Vol_info_header;
3473  for (i = 0; i <= (header_p->next_perm_volid - 1) / FILEIO_VOLINFO_INCREMENT; i++)
3474  {
3475  max_j = fileio_max_permanent_volumes (i, header_p->next_perm_volid);
3476 
3477  for (j = 0; j <= max_j; j++)
3478  {
3479  vol_info_p = &header_p->volinfo[i][j];
3480  if (vol_info_p->vdes != NULL_VOLDES)
3481  {
3482  if (((*fun) (thread_p, vol_info_p->volid, args)) == false)
3483  {
3484  return false;
3485  }
3486  }
3487  }
3488  }
3489 
3490  num_temp_vols = LOG_MAX_DBVOLID - header_p->next_temp_volid;
3491  for (i = header_p->num_volinfo_array - 1;
3492  i > (header_p->num_volinfo_array - 1
3493  - (num_temp_vols + FILEIO_VOLINFO_INCREMENT - 1) / FILEIO_VOLINFO_INCREMENT); i--)
3494  {
3495  min_j = fileio_min_temporary_volumes (i, num_temp_vols, header_p->num_volinfo_array);
3496 
3497  for (j = FILEIO_VOLINFO_INCREMENT - 1; j >= min_j; j--)
3498  {
3499  vol_info_p = &header_p->volinfo[i][j];
3500  if (vol_info_p->vdes != NULL_VOLDES)
3501  {
3502  if (((*fun) (thread_p, vol_info_p->volid, args)) == false)
3503  {
3504  return false;
3505  }
3506  }
3507  }
3508  }
3509 
3510  return true;
3511 }
3512 
3513 static bool
3515 {
3516  if (vol_info_p->vdes == NULL_VOLDES)
3517  {
3518  return false;
3519  }
3520  return (vol_info_p->vdes == arg->vdes);
3521 }
3522 
3523 static bool
3525 {
3526  if (vol_info_p->volid == NULL_VOLID)
3527  {
3528  return false;
3529  }
3530  return (vol_info_p->volid == arg->vol_id);
3531 }
3532 
3533 static bool
3535 {
3536  if (vol_info_p->volid == NULL_VOLID)
3537  {
3538  return false;
3539  }
3540  return (vol_info_p->volid > arg->vol_id);
3541 }
3542 
3543 static bool
3545 {
3546  if (vol_info_p->volid == NULL_VOLID)
3547  {
3548  return false;
3549  }
3550  return (vol_info_p->volid < arg->vol_id);
3551 }
3552 
3555 {
3556  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
3557 
3558  for (sys_vol_info_p = &fileio_Sys_vol_info_header.anchor;
3559  sys_vol_info_p != NULL && sys_vol_info_p->vdes != NULL_VOLDES; sys_vol_info_p = sys_vol_info_p->next)
3560  {
3561  if ((*apply_function) (thread_p, sys_vol_info_p, arg) == true)
3562  {
3563  return sys_vol_info_p;
3564  }
3565  }
3566 
3567  return NULL;
3568 }
3569 
3570 static bool
3572  APPLY_ARG * arg)
3573 {
3574  return (sys_vol_info_p->vdes == arg->vdes);
3575 }
3576 
3577 static bool
3579 {
3580  return (sys_vol_info_p->volid == arg->vol_id);
3581 }
3582 
3583 static bool
3585  APPLY_ARG * arg)
3586 {
3587  return (util_compare_filepath (sys_vol_info_p->vlabel, arg->vol_label) == 0);
3588 }
3589 
3590 /*
3591  * fileio_page_hexa_dump () - Hexa dump the page.
3592  * return: nothing.
3593  * data(in): source data to dump
3594  * length(in): The length of the data.
3595  */
3596 void
3597 fileio_page_hexa_dump (const char *src_data, int length)
3598 {
3599  char *log_block_string, *dest_ptr;
3600  const size_t size = length * 4;
3601  int line_no, i;
3602 
3603  dest_ptr = log_block_string = (char *) malloc (size);
3604  if (log_block_string == NULL)
3605  {
3606  return;
3607  }
3608 
3609  for (i = 0, line_no = 0; i < length; i++, src_data++)
3610  {
3611  if (i % 32 == 0)
3612  {
3613  dest_ptr += sprintf (dest_ptr, "\n%05d: ", line_no++);
3614  }
3615 
3616  dest_ptr += sprintf (dest_ptr, "%02X ", (unsigned char) (*src_data));
3617  }
3618 
3619  dest_ptr += sprintf (dest_ptr, "\n");
3620 
3621  assert ((size_t) (dest_ptr - log_block_string) < size);
3622 
3623  er_log_debug (ARG_FILE_LINE, "fileio_page_hexa_dump: data = %s\n", log_block_string);
3624 
3625  free_and_init (log_block_string);
3626 }
3627 
3628 #if !defined (WINDOWS)
3629 /*
3630  * pwrite_write_with_injected_fault () - Write buffer to file descriptor with fault injection.
3631  * return:
3632  * thread_p(in): thread entry
3633  * fd(in): file descriptor
3634  * buf(in): buffer to write
3635  * count(in): count bytes to write
3636  * offset(in): offset into file
3637  */
3638 static ssize_t
3639 pwrite_with_injected_fault (THREAD_ENTRY * thread_p, int fd, const void *buf, size_t count, off_t offset)
3640 {
3641  static bool init = false;
3642  const int mod_factor = 25000;
3643  const int block_size = 4096;
3644  int count_blocks;
3645  ssize_t r, written_nbytes;
3646  off_t unit_offset;
3647  bool fi_partial_write1_on, fi_partial_write2_on;
3648 
3649  if (init == false)
3650  {
3651  srand ((unsigned int) time (NULL));
3652  init = true;
3653  }
3654 
3655  fi_partial_write1_on = FI_INSERTED (FI_TEST_FILE_IO_WRITE_PARTS1);
3656  fi_partial_write2_on = FI_INSERTED (FI_TEST_FILE_IO_WRITE_PARTS2);
3657 
3658  if ((fi_partial_write1_on || fi_partial_write2_on) && ((rand () % mod_factor) == 0))
3659  {
3660  // simulate partial write
3661  count_blocks = count / block_size;
3662  written_nbytes = 0;
3663  for (int i = 0; i < count_blocks; i++)
3664  {
3665  if (fi_partial_write1_on)
3666  {
3667  unit_offset = i * block_size;
3668  }
3669  else
3670  {
3671  // reverse order
3672  unit_offset = ((count_blocks - 1) - i) * block_size;
3673  }
3674 
3675  r = pwrite (fd, ((char *) buf) + unit_offset, block_size, offset + unit_offset);
3676  written_nbytes += r;
3677  if (r != block_size)
3678  {
3679  return written_nbytes;
3680  }
3681 
3682  // randomly exits to remain page is partially written
3683  if ((rand () % count_blocks - 1) == 0)
3684  {
3685  char msg[1024];
3686  char *vlabel;
3687 
3688  vlabel = fileio_get_volume_label_by_fd (fd, PEEK);
3689  sprintf (msg, "fault injected to write a page to offset (%ld) of '%s'\n", offset,
3690  vlabel ? vlabel : "unknown volume");
3691  er_print_callstack (ARG_FILE_LINE, "FAULT INJECTION: RANDOM EXIT\n");
3693 
3694  // exit handler
3695  (void) fileio_synchronize (thread_p, fd, vlabel, FILEIO_SYNC_ONLY);
3696 
3697 #if !defined(NDEBUG)
3699  {
3700  fileio_page_hexa_dump ((const char *) buf, count);
3701 
3702 #if defined (SERVER_MODE) || defined (SA_MODE)
3703  /* Verify page correctness before the crash, for proper recovery purpose. */
3704  if (fileio_is_permanent_volume_descriptor (thread_p, fd))
3705  {
3706  /* Permanent data volume. */
3707  int error_code;
3708  bool is_page_corrupted;
3709 
3710  error_code = fileio_page_check_corruption (thread_p, (FILEIO_PAGE *) buf, &is_page_corrupted);
3711  assert (error_code == NO_ERROR && is_page_corrupted == false);
3712  }
3713  else
3714  {
3715  /* sys volume ? */
3716  int rv;
3717  FILEIO_SYSTEM_VOLUME_INFO *sys_volinfo;
3718  APPLY_ARG arg = { 0 };
3719 
3720  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
3721  arg.vdes = fd;
3722  sys_volinfo =
3724  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
3725  if (sys_volinfo)
3726  {
3727  logpb_debug_check_log_page (thread_p, (void *) buf);
3728  }
3729  }
3730 #endif /* defined (SERVER_MODE) || (SA_MODE) */
3731  }
3732 
3733 #endif /* defined (NDEBUG) */
3734  // exit
3735  _exit (0);
3736  }
3737  }
3738 
3739  return written_nbytes;
3740  }
3741 
3742  return pwrite (fd, buf, count, offset);
3743 }
3744 #endif
3745 
3746 #if defined(HPUX) && !defined(IA64)
3747 /*
3748  * pread () -
3749  * return:
3750  * fd(in):
3751  * buf(in):
3752  * nbytes(in):
3753  * offset(in):
3754  *
3755  * Note: Like HP-UX 11, the positioned I/O may not directly available in some
3756  * systems. In that case, use the following simulated positioned I/O
3757  * routines.
3758  */
3759 ssize_t
3760 pread (int fd, void *buf, size_t nbytes, off_t offset)
3761 {
3762  struct aiocb io;
3763  const struct aiocb *list[1];
3764  int err;
3765 
3766  io.aio_fildes = fd;
3767  io.aio_offset = offset;
3768  io.aio_buf = buf;
3769  io.aio_nbytes = nbytes;
3770  io.aio_reqprio = 0;
3771  io.aio_sigevent.sigev_notify = SIGEV_NONE;
3772 
3773  err = aio_read (&io); /* atomically reads at offset */
3774  if (err != 0)
3775  {
3776  return (err);
3777  }
3778 
3779  list[0] = &io;
3780 
3781  err = aio_suspend (list, 1, NULL); /* wait for IO to complete */
3782  if (err != 0)
3783  {
3784  return (err);
3785  }
3786 
3787  return aio_return (&io);
3788 }
3789 
3790 /*
3791  * pwrite () -
3792  * return:
3793  * fd(in):
3794  * buf(in):
3795  * nbytes(in):
3796  * offset(in):
3797  */
3798 ssize_t
3799 pwrite (int fd, const void *buf, size_t nbytes, off_t offset)
3800 {
3801  struct aiocb io;
3802  const struct aiocb *list[1];
3803  int err;
3804 
3805  io.aio_fildes = fd;
3806  io.aio_offset = offset;
3807  io.aio_buf = buf;
3808  io.aio_nbytes = nbytes;
3809  io.aio_reqprio = 0;
3810  io.aio_sigevent.sigev_notify = SIGEV_NONE;
3811 
3812  err = aio_write (&io); /* atomically writes at offset */
3813  if (err != 0)
3814  {
3815  return (err);
3816  }
3817 
3818  list[0] = &io;
3819 
3820  err = aio_suspend (list, 1, NULL); /* wait for IO to complete */
3821  if (err != 0)
3822  {
3823  return (err);
3824  }
3825 
3826  return aio_return (&io);
3827 }
3828 #elif defined(WINDOWS) && defined(SERVER_MODE)
3829 /*
3830  * fileio_get_volume_mutex () - FIND VOLUME MUTEX GIVEN DESCRIPTOR
3831  * return: I/O volume mutex
3832  * vdes(in): Volume descriptor
3833  */
3834 static pthread_mutex_t *
3835 fileio_get_volume_mutex (THREAD_ENTRY * thread_p, int vdes)
3836 {
3837  FILEIO_VOLUME_INFO *volinfo;
3838  FILEIO_SYSTEM_VOLUME_INFO *sys_volinfo;
3839  int rv;
3840  APPLY_ARG arg = { 0 };
3841 
3843 
3844  /* perm/temp volume ? */
3845 
3846  arg.vdes = vdes;
3848  if (volinfo)
3849  {
3850  return &volinfo->vol_mutex;
3851  }
3852 
3853  arg.vdes = vdes;
3855  if (volinfo)
3856  {
3857  return &volinfo->vol_mutex;
3858  }
3859 
3860  /* sys volume ? */
3861  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
3862 
3863  arg.vdes = vdes;
3865  if (sys_volinfo)
3866  {
3867  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
3868  return &sys_volinfo->sysvol_mutex;
3869  }
3870 
3871  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
3872  return NULL;
3873 }
3874 #endif /* WINDOWS && SERVER_MODE */
3875 
3876 /*
3877  * fileio_os_read () - helper for fileio_read
3878  * return: the number of bytes read is returned. On error, error code.
3879  * vol_fd(in): Volume descriptor
3880  * io_page_p(out): Address where content of page is stored. Must be of page_size long
3881  * count(in): the number of bytes to be read
3882  * offset(in): starting file offset
3883  */
3884 static ssize_t
3885 fileio_os_read (THREAD_ENTRY * thread_p, int vol_fd, void *io_page_p, size_t count, off_t offset)
3886 {
3887 #if !defined (SERVER_MODE)
3888  /* Locate the desired page */
3889  if (lseek (vol_fd, offset, SEEK_SET) != offset)
3890  {
3891  return ER_FAILED;
3892  }
3893 
3894  /* Read the desired page */
3895  return read (vol_fd, io_page_p, count);
3896 #elif defined (WINDOWS)
3897  // TODO: replace it with ReadFile
3898  ssize_t nbytes;
3899  int rv;
3900  pthread_mutex_t *io_mutex;
3901  static pthread_mutex_t io_mutex_instance = PTHREAD_MUTEX_INITIALIZER;
3902 
3903  io_mutex = fileio_get_volume_mutex (thread_p, vol_fd);
3904  if (io_mutex == NULL)
3905  {
3906  io_mutex = &io_mutex_instance;
3907  }
3908 
3909  rv = pthread_mutex_lock (io_mutex);
3910  if (rv != 0)
3911  {
3913  return ER_FAILED;
3914  }
3915 
3916  /* Locate the desired page */
3917  if (lseek (vol_fd, offset, SEEK_SET) != offset)
3918  {
3919  pthread_mutex_unlock (io_mutex);
3920  return ER_FAILED;
3921  }
3922 
3923  /* Read the desired page */
3924  nbytes = read (vol_fd, io_page_p, (unsigned int) count);
3925  if (pthread_mutex_unlock (io_mutex) != 0)
3926  {
3928  return ER_FAILED;
3929  }
3930 
3931  return nbytes;
3932 #else /* WINDOWS */
3933  return pread (vol_fd, io_page_p, count, offset);
3934 #endif
3935 }
3936 
3937 /*
3938  * fileio_read () - READ A PAGE FROM DISK
3939  * return:
3940  * vol_fd(in): Volume descriptor
3941  * io_page_p(out): Address where content of page is stored. Must be of page_size long
3942  * page_id(in): Page identifier
3943  * page_size(in): Page size
3944  *
3945  * Note: Read the content of the page described by page_id onto the
3946  * given io_page_p buffer. The io_page_p must be page_size long.
3947  */
3948 
3949 void *
3950 fileio_read (THREAD_ENTRY * thread_p, int vol_fd, void *io_page_p, PAGEID page_id, size_t page_size)
3951 {
3952 #if defined (EnableThreadMonitoring)
3953  TSC_TICKS start_tick, end_tick;
3954  TSCTIMEVAL elapsed_time;
3955 #endif
3956  off_t offset = FILEIO_GET_FILE_SIZE (page_size, page_id);
3957  ssize_t nbytes;
3958  bool is_retry = true;
3959 
3960 #if defined (EnableThreadMonitoring)
3962  {
3963  tsc_getticks (&start_tick);
3964  }
3965 #endif
3966 
3967  while (is_retry == true)
3968  {
3969  is_retry = false;
3970 
3971  nbytes = fileio_os_read (thread_p, vol_fd, io_page_p, page_size, offset);
3972  if (nbytes != (ssize_t) page_size)
3973  {
3974  if (nbytes == 0)
3975  {
3976  /* This is an end of file. We are trying to read beyond the allocated disk space */
3979  return NULL;
3980  }
3981 
3982  if (errno == EINTR)
3983  {
3984  is_retry = true;
3985  }
3986  else
3987  {
3990  return NULL;
3991  }
3992  }
3993  }
3994 
3995 #if defined (EnableThreadMonitoring)
3997  {
3998  tsc_getticks (&end_tick);
3999  tsc_elapsed_time_usec (&elapsed_time, end_tick, start_tick);
4000  }
4001 
4002  if (MONITOR_WAITING_THREAD (elapsed_time))
4003  {
4006  er_log_debug (ARG_FILE_LINE, "fileio_read: %6d.%06d\n", elapsed_time.tv_sec, elapsed_time.tv_usec);
4007  }
4008 #endif
4009 
4011  return io_page_p;
4012 }
4013 
4014 /*
4015  * fileio_write_or_add_to_dwb () - Write a page to disk if DWb disabled, otherwise add it to DWB
4016  * return: io_page_p on success, NULL on failure
4017  * vol_fd(in): Volume descriptor
4018  * io_page_p(in): In-memory address where the current content of page resides
4019  * page_id(in): Page identifier
4020  * page_size(in): Page size
4021  *
4022  */
4023 void *
4024 fileio_write_or_add_to_dwb (THREAD_ENTRY * thread_p, int vol_fd, FILEIO_PAGE * io_page_p, PAGEID page_id,
4025  size_t page_size)
4026 {
4027 #if !defined (CS_MODE)
4028  bool skip_flush = false;
4029  DWB_SLOT *p_dwb_slot = NULL;
4030  VPID vpid;
4031  FILEIO_VOLUME_INFO *vol_info_p;
4032  APPLY_ARG arg = { 0 };
4033  int error_code;
4034  FILEIO_WRITE_MODE write_mode;
4035 
4036  assert (vol_fd != NULL_VOLDES && io_page_p != NULL);
4037 
4038  skip_flush = dwb_is_created ();
4039  if (skip_flush)
4040  {
4042 
4043  arg.vdes = vol_fd;
4045  if (vol_info_p)
4046  {
4047  /* Permanent volumes - uses DWB. */
4048  VPID_SET (&vpid, vol_info_p->volid, page_id);
4049 
4050  io_page_p->prv.volid = vol_info_p->volid;
4051  io_page_p->prv.pageid = page_id;
4052 
4053  error_code = dwb_add_page (thread_p, io_page_p, &vpid, &p_dwb_slot);
4054  if (error_code != NO_ERROR)
4055  {
4056  return NULL;
4057  }
4058  else if (p_dwb_slot != NULL)
4059  {
4060  /* The page was successfully added to DWB. It will be written later. */
4061  return io_page_p;
4062  }
4063 
4064  /* DWB disabled, write the page. */
4065  }
4066  /* Not permanent volume - write the page. */
4067  }
4068 
4070 
4071  return fileio_write (thread_p, vol_fd, io_page_p, page_id, page_size, write_mode);
4072 #else
4073  return fileio_write (thread_p, vol_fd, io_page_p, page_id, page_size, FILEIO_WRITE_DEFAULT_WRITE);
4074 #endif
4075 }
4076 
4077 /*
4078  * fileio_os_write () - helper for fileio_write
4079  * return: the number of bytes written is returned. On error, error code.
4080  * vol_fd(in): Volume descriptor
4081  * io_page_p(in): In-memory address where the current content of page resides
4082  * count(in): the number of bytes to be written
4083  * offset(in): starting file offset
4084  *
4085  */
4086 static ssize_t
4087 fileio_os_write (THREAD_ENTRY * thread_p, int vol_fd, void *io_page_p, size_t count, off_t offset)
4088 {
4089 #if !defined (SERVER_MODE)
4090  if (lseek (vol_fd, offset, SEEK_SET) != offset)
4091  {
4092  return ER_FAILED;
4093  }
4094 
4095  /* write the page */
4096  return write (vol_fd, io_page_p, count);
4097 #elif defined (WINDOWS)
4098  // TODO: replace it with WriteFile
4099  int rv, nbytes;
4100  pthread_mutex_t *io_mutex;
4101  static pthread_mutex_t io_mutex_instance = PTHREAD_MUTEX_INITIALIZER;
4102 
4103  io_mutex = fileio_get_volume_mutex (thread_p, vol_fd);
4104  if (io_mutex == NULL)
4105  {
4106  io_mutex = &io_mutex_instance;
4107  }
4108 
4109  rv = pthread_mutex_lock (io_mutex);
4110  if (rv != 0)
4111  {
4113  return ER_FAILED;
4114  }
4115 
4116  if (lseek (vol_fd, offset, SEEK_SET) != offset)
4117  {
4118  pthread_mutex_unlock (io_mutex);
4119  return ER_FAILED;
4120  }
4121 
4122  /* write the page */
4123  nbytes = write (vol_fd, io_page_p, (unsigned int) count);
4124 
4125  pthread_mutex_unlock (io_mutex);
4126 
4127  return (ssize_t) nbytes;
4128 #elif defined (NDEBUG)
4129  /* release mode */
4130  return pwrite (vol_fd, io_page_p, count, offset);
4131 #else
4132  /* server debugging mode */
4133  return pwrite_with_injected_fault (thread_p, vol_fd, io_page_p, count, offset);
4134 #endif
4135 }
4136 
4137 /*
4138  * fileio_write () - WRITE A PAGE TO DISK
4139  * return: io_page_p on success, NULL on failure
4140  * vol_fd(in): Volume descriptor
4141  * io_page_p(in): In-memory address where the current content of page resides
4142  * page_id(in): Page identifier
4143  * page_size(in): Page size
4144  * write_mode(in): FILEIO_WRITE_NO_COMPENSATE_WRITE skips page flush
4145  *
4146  * Note: Write the content of the page described by page_id to disk. The content of the page is stored onto io_page_p
4147  * buffer which is page_size long.
4148  */
4149 void *
4150 fileio_write (THREAD_ENTRY * thread_p, int vol_fd, void *io_page_p, PAGEID page_id, size_t page_size,
4151  FILEIO_WRITE_MODE write_mode)
4152 {
4153 #if defined (EnableThreadMonitoring)
4154  TSC_TICKS start_tick, end_tick;
4155  TSCTIMEVAL elapsed_time;
4156 #endif
4157  ssize_t nbytes_written;
4158  off_t offset = FILEIO_GET_FILE_SIZE (page_size, page_id);
4159  bool is_retry = true;
4160 
4161 #if defined (EnableThreadMonitoring)
4163  {
4164  tsc_getticks (&start_tick);
4165  }
4166 #endif
4167 
4168  while (is_retry == true)
4169  {
4170  is_retry = false;
4171 
4172  nbytes_written = fileio_os_write (thread_p, vol_fd, io_page_p, page_size, offset);
4173  if (nbytes_written != (ssize_t) page_size)
4174  {
4175  if (errno == EINTR)
4176  {
4177  is_retry = true;
4178  }
4179  else if (errno == ENOSPC)
4180  {
4183 
4184 #if defined (SERVER_MODE) && !defined (WINDOWS)
4185  syslog (LOG_ALERT, "[CUBRID] %s () at %s:%d %m", __func__, __FILE__, __LINE__);
4186 #endif
4187  return NULL;
4188  }
4189  else
4190  {
4193  return NULL;
4194  }
4195  }
4196  }
4197 
4198 #if defined (EnableThreadMonitoring)
4200  {
4201  tsc_getticks (&end_tick);
4202  tsc_elapsed_time_usec (&elapsed_time, end_tick, start_tick);
4203  }
4204 
4205  if (MONITOR_WAITING_THREAD (elapsed_time))
4206  {
4209  er_log_debug (ARG_FILE_LINE, "fileio_write: %6d.%06d\n", elapsed_time.tv_sec, elapsed_time.tv_usec);
4210  }
4211 #endif
4212 
4213  if (write_mode == FILEIO_WRITE_DEFAULT_WRITE)
4214  {
4215  fileio_compensate_flush (thread_p, vol_fd, 1);
4216  }
4217 
4219 
4220  return io_page_p;
4221 }
4222 
4223 /*
4224  * fileio_read_pages () -
4225  */
4226 void *
4227 fileio_read_pages (THREAD_ENTRY * thread_p, int vol_fd, char *io_pages_p, PAGEID page_id, int num_pages,
4228  size_t page_size)
4229 {
4230 #if defined (EnableThreadMonitoring)
4231  TSC_TICKS start_tick, end_tick;
4232  TSCTIMEVAL elapsed_time;
4233 #endif
4234  off_t offset;
4235  ssize_t nbytes_read;
4236  size_t nbytes_to_be_read;
4237 
4238  assert (num_pages > 0);
4239 
4240  offset = FILEIO_GET_FILE_SIZE (page_size, page_id);
4241  nbytes_to_be_read = ((size_t) page_size) * ((size_t) num_pages);
4242 
4243 #if defined (EnableThreadMonitoring)
4245  {
4246  tsc_getticks (&start_tick);
4247  }
4248 #endif
4249 
4250  while (nbytes_to_be_read > 0)
4251  {
4252  nbytes_read = fileio_os_read (thread_p, vol_fd, io_pages_p, nbytes_to_be_read, offset);
4253  if (nbytes_read <= 0)
4254  {
4255  if (nbytes_read == 0)
4256  {
4257  return NULL;
4258  }
4259 
4260  switch (errno)
4261  {
4262  case EINTR:
4263  case EAGAIN:
4264  continue;
4265 #if !defined(WINDOWS)
4266  case EOVERFLOW:
4267  return NULL;
4268 #endif /* !WINDOWS */
4269  default:
4270  {
4273  return NULL;
4274  }
4275  }
4276  }
4277 
4278  offset += nbytes_read;
4279  io_pages_p += nbytes_read;
4280  nbytes_to_be_read -= nbytes_read;
4281  }
4282 
4283 #if defined (EnableThreadMonitoring)
4285  {
4286  tsc_getticks (&end_tick);
4287  tsc_elapsed_time_usec (&elapsed_time, end_tick, start_tick);
4288  }
4289 
4290  if (MONITOR_WAITING_THREAD (elapsed_time))
4291  {
4294  er_log_debug (ARG_FILE_LINE, "fileio_read_pages: %6d.%06d\n", elapsed_time.tv_sec, elapsed_time.tv_usec);
4295  }
4296 #endif
4297 
4299  return io_pages_p;
4300 }
4301 
4302 /*
4303  * fileio_write_pages () - write the content of several contiguous pages to disk
4304  * return: io_page_p on success, NULL on failure
4305  * thread_p(in): Thread entry
4306  * vol_fd(in): Volume descriptor
4307  * io_page_p(in): In-memory address where the pages resides
4308  * page_id(in): First page identifier
4309  * num_pages(in): Number of pages to flush
4310  * page_size(in): Page size
4311  * write_mode(in): FILEIO_WRITE_NO_COMPENSATE_WRITE skips page flush
4312  */
4313 void *
4314 fileio_write_pages (THREAD_ENTRY * thread_p, int vol_fd, char *io_pages_p, PAGEID page_id, int num_pages,
4315  size_t page_size, FILEIO_WRITE_MODE write_mode)
4316 {
4317 #if defined (EnableThreadMonitoring)
4318  TSC_TICKS start_tick, end_tick;
4319  TSCTIMEVAL elapsed_time;
4320 #endif
4321  off_t offset;
4322  ssize_t nbytes_written;
4323  size_t nbytes_to_be_written;
4324 
4325  assert (num_pages > 0);
4326 
4327  offset = FILEIO_GET_FILE_SIZE (page_size, page_id);
4328  nbytes_to_be_written = ((size_t) page_size) * ((size_t) num_pages);
4329 
4330 #if defined (EnableThreadMonitoring)
4332  {
4333  tsc_getticks (&start_tick);
4334  }
4335 #endif
4336 
4337  while (nbytes_to_be_written > 0)
4338  {
4339  nbytes_written = fileio_os_write (thread_p, vol_fd, io_pages_p, nbytes_to_be_written, offset);
4340  if (nbytes_written <= 0)
4341  {
4342  if (nbytes_written == 0)
4343  {
4344  return NULL;
4345  }
4346 
4347  switch (errno)
4348  {
4349  case EINTR:
4350  case EAGAIN:
4351  continue;
4352 #if !defined(WINDOWS)
4353  case EOVERFLOW:
4354  return NULL;
4355 #endif /* !WINDOWS */
4356  default:
4357  {
4360  return NULL;
4361  }
4362  }
4363  }
4364 
4365  offset += nbytes_written;
4366  io_pages_p += nbytes_written;
4367  nbytes_to_be_written -= nbytes_written;
4368  }
4369 
4370 #if defined (EnableThreadMonitoring)
4372  {
4373  tsc_getticks (&end_tick);
4374  tsc_elapsed_time_usec (&elapsed_time, end_tick, start_tick);
4375  }
4376 
4377  if (MONITOR_WAITING_THREAD (elapsed_time))
4378  {
4381  er_log_debug (ARG_FILE_LINE, "fileio_write_pages: %6d.%06d\n", elapsed_time.tv_sec, elapsed_time.tv_usec);
4382  }
4383 #endif
4384 
4385  if (write_mode == FILEIO_WRITE_DEFAULT_WRITE)
4386  {
4387  fileio_compensate_flush (thread_p, vol_fd, num_pages);
4388  }
4389 
4390  perfmon_add_stat (thread_p, PSTAT_FILE_NUM_IOWRITES, num_pages);
4391  return io_pages_p;
4392 }
4393 
4394 /*
4395  * fileio_writev () - WRITE A SET OF CONTIGUOUS PAGES TO DISK
4396  * return: io_pgptr on success, NULL on failure
4397  * vol_fd(in): Volume descriptor
4398  * arrayof_io_pgptr(in): An array address to address where the current content of pages reside
4399  * start_page_id(in): Page identifier of first page
4400  * npages(in): Number of consecutive pages
4401  * page_size(in): Page size
4402  *
4403  * Note: Write the content of the consecutive pages described by start_pageid to disk. The content of the pages are
4404  * address by the io_pgptr array. Each io_pgptr buffer is page size long.
4405  *
4406  * io_pgptr[0] -->> start_pageid
4407  * io_pgptr[1] -->> start_pageid + 1
4408  * ...
4409  * io_pgptr[npages - 1] -->> start_pageid + npages - 1
4410  */
4411 void *
4412 fileio_writev (THREAD_ENTRY * thread_p, int vol_fd, void **io_page_array, PAGEID start_page_id, DKNPAGES npages,
4413  size_t page_size)
4414 {
4415  int i;
4417 
4418 #if !defined (CS_MODE)
4420 #endif
4421 
4422  for (i = 0; i < npages; i++)
4423  {
4424  if (fileio_write (thread_p, vol_fd, io_page_array[i], start_page_id + i, page_size, write_mode) == NULL)
4425  {
4426  return NULL;
4427  }
4428  }
4429 
4430  return io_page_array[0];
4431 }
4432 
4433 /*
4434  * fileio_synchronize () - Synchronize a database volume's state with that on disk
4435  * return: vdes or NULL_VOLDES
4436  * vol_fd(in): Volume descriptor
4437  * vlabel(in): Volume label
4438  * sync_dwb(in): FILEIO_SYNC_ALSO_FLUSH_DWB if needs sync dwb
4439  */
4440 int
4441 fileio_synchronize (THREAD_ENTRY * thread_p, int vol_fd, const char *vlabel, FILEIO_SYNC_OPTION sync_dwb)
4442 {
4443  int ret = NO_ERROR;
4444  bool all_sync = false;
4445 #if defined (EnableThreadMonitoring)
4446  TSC_TICKS start_tick, end_tick;
4447  TSCTIMEVAL elapsed_time;
4448 #endif
4449 #if defined (SERVER_MODE)
4450  static pthread_mutex_t inc_cnt_mutex = PTHREAD_MUTEX_INITIALIZER;
4451  int r;
4452 #endif
4453  static int inc_cnt = 0;
4454 
4456  {
4457 #if defined (SERVER_MODE)
4458  r = pthread_mutex_lock (&inc_cnt_mutex);
4459 #endif
4460  if (++inc_cnt >= prm_get_integer_value (PRM_ID_SUPPRESS_FSYNC))
4461  {
4462  inc_cnt = 0;
4463  }
4464  else
4465  {
4466 #if defined (SERVER_MODE)
4467  pthread_mutex_unlock (&inc_cnt_mutex);
4468 #endif
4469  return vol_fd;
4470  }
4471 #if defined (SERVER_MODE)
4472  pthread_mutex_unlock (&inc_cnt_mutex);
4473 #endif
4474  }
4475 
4476 #if defined (EnableThreadMonitoring)
4478  {
4479  tsc_getticks (&start_tick);
4480  }
4481 #endif
4482 
4483 #if !defined (CS_MODE)
4484  if (sync_dwb == FILEIO_SYNC_ALSO_FLUSH_DWB && fileio_is_permanent_volume_descriptor (thread_p, vol_fd))
4485  {
4486  ret = dwb_flush_force (thread_p, &all_sync);
4487  }
4488 #endif
4489 
4490  /* If all_sync is true, everything was synchronized. This happens when DWB is completely flushed. */
4491  if (ret == NO_ERROR && all_sync == false)
4492  {
4493  ret = fsync (vol_fd);
4494  }
4495 
4496 #if defined (EnableThreadMonitoring)
4498  {
4499  tsc_getticks (&end_tick);
4500  tsc_elapsed_time_usec (&elapsed_time, end_tick, start_tick);
4501  }
4502 #endif
4503 
4504  if (ret != 0)
4505  {
4506  /* sync error is not alwasy handled and I am not sure a proper safe handling is possible: raise as fatal error */
4507  er_set_with_oserror (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_SYNC, 1, (vlabel ? vlabel : "Unknown"));
4508  return NULL_VOLDES;
4509  }
4510  else
4511  {
4512 #if defined (EnableThreadMonitoring)
4513  if (MONITOR_WAITING_THREAD (elapsed_time))
4514  {
4517  er_log_debug (ARG_FILE_LINE, "fileio_synchronize: %6d.%06d\n", elapsed_time.tv_sec, elapsed_time.tv_usec);
4518  }
4519 #endif
4520 
4522  return vol_fd;
4523  }
4524 }
4525 
4526 /*
4527  * fileio_synchronize_bg_archive_volume () -
4528  * return:
4529  */
4530 static int
4532 {
4533  APPLY_ARG arg = { 0 };
4534 
4537  return NO_ERROR;
4538 }
4539 
4540 /*
4541  * fileio_synchronize_sys_volume () -
4542  * return:
4543  * vol_info_p(in):
4544  */
4545 static bool
4547 {
4548  bool found = false;
4549 
4550  if (sys_vol_info_p->vdes != NULL_VOLDES)
4551  {
4552  /* sync when match is found or arg.vol_id is given as NULL_VOLID for all sys volumes. */
4553  if (arg->vol_id == NULL_VOLID)
4554  {
4555  /* fall through */
4556  ;
4557  }
4558  else if (sys_vol_info_p->volid == arg->vol_id)
4559  {
4560  found = true;
4561  }
4562  else
4563  {
4564  /* irrelevant volume */
4565  return false;
4566  }
4567 
4568 
4569  /* System volume. No need to sync DWB. */
4570  fileio_synchronize (thread_p, sys_vol_info_p->vdes, sys_vol_info_p->vlabel, FILEIO_SYNC_ONLY);
4571  }
4572 
4573  return found;
4574 }
4575 
4576 /*
4577  * fileio_synchronize_volume () -
4578  * return:
4579  * vol_info_p(in):
4580  *
4581  * Note : This function does not synchronize DWB.
4582  */
4583 static bool
4585 {
4586  bool found = false;
4587 
4588  if (vol_info_p->vdes != NULL_VOLDES)
4589  {
4590  /* sync when match is found or arg.vol_id is given as NULL_VOLID for all sys volumes. */
4591  if (arg->vol_id == NULL_VOLID)
4592  {
4593  /* fall through */
4594  ;
4595  }
4596  else if (vol_info_p->volid == arg->vol_id)
4597  {
4598  found = true;
4599  }
4600  else
4601  {
4602  /* irrelevant volume */
4603  return false;
4604  }
4605 
4606  fileio_synchronize (thread_p, vol_info_p->vdes, vol_info_p->vlabel, FILEIO_SYNC_ONLY);
4607  }
4608 
4609  return found;
4610 }
4611 
4612 /*
4613  * fileio_synchronize_all () - Synchronize all database volumes with disk
4614  * return:
4615  * include_log(in):
4616  */
4617 int
4618 fileio_synchronize_all (THREAD_ENTRY * thread_p, bool is_include)
4619 {
4620  int success = NO_ERROR;
4621  bool all_sync = false;
4622  APPLY_ARG arg = { 0 };
4623 #if defined (SERVER_MODE) || defined (SA_MODE)
4624  PERF_UTIME_TRACKER time_track;
4625 
4626  PERF_UTIME_TRACKER_START (thread_p, &time_track);
4627 #endif /* defined (SERVER_MODE) || defined (SA_MODE) */
4628 
4629  arg.vol_id = NULL_VOLID;
4630 
4631  er_stack_push ();
4632 
4633  if (is_include)
4634  {
4635  /* Flush logs. */
4637  }
4638 
4639 #if !defined (CS_MODE)
4640  /* Flush DWB before volume data. */
4641  success = dwb_flush_force (thread_p, &all_sync);
4642 #endif
4643 
4644  /* Check whether the volumes were flushed. */
4645  if (success == NO_ERROR && all_sync == false)
4646  {
4647  /* Flush volume data. */
4649 
4650  if (er_errid () == ER_IO_SYNC)
4651  {
4652  success = ER_FAILED;
4653  }
4654  }
4655 
4656  er_stack_pop ();
4657 
4658 #if defined (SERVER_MODE) || defined (SA_MODE)
4659  PERF_UTIME_TRACKER_TIME (thread_p, &time_track, PSTAT_FILE_IOSYNC_ALL);
4660 #endif /* defined (SERVER_MODE) || defined (SA_MODE) */
4661 
4662  return success;
4663 }
4664 
4665 #if defined(ENABLE_UNUSED_FUNCTION)
4666 /*
4667  * fileio_read_user_area () - READ A PORTION OF THE USER AREA OF THE GIVEN PAGE
4668  * return: area on success, NULL on failure
4669  * vdes(in): Volume descriptor
4670  * pageid(in): Page identifier
4671  * start_offset(in): Start offset of interested content in page
4672  * nbytes(in): Length of the content of page to copy
4673  * area(out):
4674  *
4675  * Note: Copy a portion of the content of the user area of the page described
4676  * by pageid onto the given area. The area must be big enough to hold
4677  * the needed content
4678  */
4679 void *
4680 fileio_read_user_area (THREAD_ENTRY * thread_p, int vol_fd, PAGEID page_id, off_t start_offset, size_t nbytes,
4681  void *area_p)
4682 {
4683  off_t offset;
4684  bool is_retry = true;
4685  FILEIO_PAGE *io_page_p;
4686 #if defined(WINDOWS) && defined(SERVER_MODE)
4687  pthread_mutex_t io_mutex;
4688  int rv;
4689  int actual_nread;
4690 #endif /* WINDOWS && SERVER_MODE */
4691 
4692  io_page_p = (FILEIO_PAGE *) malloc (IO_PAGESIZE);
4693  if (io_page_p == NULL)
4694  {
4696  return NULL;
4697  }
4698 
4699  /* Find the offset intop the user area on the desired page */
4700  offset = FILEIO_GET_FILE_SIZE (IO_PAGESIZE, page_id);
4701 
4702  while (is_retry == true)
4703  {
4704  is_retry = false;
4705 
4706 #if !defined(SERVER_MODE)
4707  /* Locate the desired page */
4708  if (lseek (vol_fd, offset, SEEK_SET) != offset)
4709  {
4710  if (io_page_p != NULL)
4711  {
4712  free_and_init (io_page_p);
4713  }
4714 
4717  return NULL;
4718  }
4719 
4720  /* Read the desired page */
4721  if (read (vol_fd, io_page_p, IO_PAGESIZE) != IO_PAGESIZE)
4722 #elif defined(WINDOWS)
4723  io_mutex = fileio_get_volume_mutex (thread_p, vol_fd);
4724  rv = pthread_mutex_lock (&io_mutex);
4725  if (rv != 0)
4726  {
4728  return NULL;
4729  }
4730 
4731  /* Locate the desired page */
4732  if (lseek (vol_fd, offset, SEEK_SET) != offset)
4733  {
4736  pthread_mutex_unlock (&io_mutex);
4737  return NULL;
4738  }
4739 
4740  /* Read the desired page */
4741  actual_nread = read (vol_fd, io_page_p, IO_PAGESIZE);
4742  if (pthread_mutex_unlock (&io_mutex) != 0)
4743  {
4745  return NULL;
4746  }
4747  if (actual_nread != IO_PAGESIZE)
4748 #else /* WINDOWS */
4749  if (pread (vol_fd, io_page_p, IO_PAGESIZE, offset) != IO_PAGESIZE)
4750 #endif /* WINDOWS */
4751  {
4752  if (errno == EINTR)
4753  {
4754  is_retry = true;
4755  }
4756  else
4757  {
4758  if (io_page_p != NULL)
4759  {
4760  free_and_init (io_page_p);
4761  }
4762 
4765  return NULL;
4766  }
4767  }
4768  }
4769 
4770  memcpy (area_p, io_page_p->page + start_offset, nbytes);
4771 
4772  if (io_page_p != NULL)
4773  {
4774  free_and_init (io_page_p);
4775  }
4776 
4778  return area_p;
4779 }
4780 
4781 /*
4782  * fileio_write_user_area () - READ A PORTION OF THE USER AREA OF THE GIVEN PAGE
4783  * return: area on success, NULL on failure
4784  * vdes(in): Volume descriptor
4785  * pageid(in): Page identifier
4786  * start_offset(in): Start offset of interested content in page
4787  * nbytes(in): Length of the content of page to copy
4788  * area(out):
4789  *
4790  * Note: Copy a portion of the content of the user area of the page described
4791  * by pageid onto the given area. The area must be big enough to hold
4792  * the needed content
4793  */
4794 void *
4795 fileio_write_user_area (THREAD_ENTRY * thread_p, int vol_fd, PAGEID page_id, off_t start_offset, int nbytes,
4796  void *area_p)
4797 {
4798  off_t offset;
4799  bool is_retry = true;
4800  FILEIO_PAGE *io_page_p = NULL;
4801  void *write_p;
4802  struct stat stat_buf;
4803 #if defined(WINDOWS) && defined(SERVER_MODE)
4804  int actual_nwrite, rv;
4805  pthread_mutex_t io_mutex;
4806 #endif /* WINDOWS && SERVER_MODE */
4807 
4808  if (fstat (vol_fd, &stat_buf) != 0)
4809  {
4812  return NULL;
4813  }
4814 
4815 #if defined(WINDOWS)
4816  /* Find the offset intop the user area on the desired page */
4817  offset = (FILEIO_GET_FILE_SIZE (IO_PAGESIZE, page_id) + offsetof (FILEIO_PAGE, page));
4818 
4819  /* Add the starting offset */
4820  offset += start_offset;
4821 
4822  write_p = area_p;
4823 #else /* WINDOWS */
4824  if (S_ISREG (stat_buf.st_mode)) /* regular file */
4825  {
4826  /* Find the offset intop the user area on the desired page */
4827  offset = (FILEIO_GET_FILE_SIZE (IO_PAGESIZE, page_id) + offsetof (FILEIO_PAGE, page));
4828 
4829  /* Add the starting offset */
4830  offset += start_offset;
4831 
4832  write_p = area_p;
4833 
4834  }
4835  else if (S_ISCHR (stat_buf.st_mode)) /* Raw device */
4836  {
4837  offset = FILEIO_GET_FILE_SIZE (IO_PAGESIZE, page_id);
4838  if (nbytes != DB_PAGESIZE)
4839  {
4842  return NULL;
4843 
4844  }
4845 
4846  io_page_p = (FILEIO_PAGE *) malloc (IO_PAGESIZE);
4847  if (io_page_p == NULL)
4848  {
4850  return NULL;
4851  }
4852 
4853  (void) fileio_initialize_res (thread_p, io_page_p, IO_PAGESIZE);
4854  memcpy (io_page_p->page, area_p, nbytes);
4855 
4856  write_p = (void *) io_page_p;
4857  nbytes = IO_PAGESIZE;
4858  }
4859  else
4860  {
4863  return NULL;
4864  }
4865 #endif /* WINDOWS */
4866 
4867  while (is_retry == true)
4868  {
4869  is_retry = false;
4870 
4871  nbytes_written = fileio_os_write (thread_p, vol_fd, write_p, nbytes, offset);
4872  if (nbytes_written != nbytes)
4873  {
4874  if (errno == EINTR)
4875  {
4876  is_retry = true;
4877  }
4878  else if (errno == ENOSPC)
4879  {
4882  goto error;
4883  }
4884  else
4885  {
4888  goto error;
4889  }
4890  }
4891  }
4892 
4893  if (io_page_p != NULL)
4894  {
4895  free_and_init (io_page_p);
4896  }
4897 
4898  fileio_compensate_flush (thread_p, vol_fd, 1);
4900  return area_p;
4901 
4902 error:
4903  if (io_page_p != NULL)
4904  {
4905  free_and_init (io_page_p);
4906  }
4907 
4908  return NULL;
4909 }
4910 #endif
4911 
4912 /*
4913  * fileio_get_number_of_volume_pages () - Find the size of the volume in number of pages
4914  * return: Num pages
4915  * vol_fd(in): Volume descriptor
4916  */
4917 DKNPAGES
4919 {
4920  off_t offset;
4921 
4922  offset = lseek (vol_fd, 0L, SEEK_END);
4923  return (DKNPAGES) (offset / page_size);
4924 
4925 }
4926 
4927 /*
4928  * fileio_get_number_of_partition_free_pages () - Find the number of free pages in the given
4929  * OS disk partition
4930  * return: number of free pages
4931  * path(in): Path to disk partition
4932  *
4933  * Note: The number of pages is in the size of the database system not
4934  * the size of the OS system.
4935  */
4936 int
4938 {
4939 #if defined(WINDOWS)
4940  return (free_space (path_p, (int) IO_PAGESIZE));
4941 #else /* WINDOWS */
4942  int vol_fd;
4943  INT64 npages_of_partition = -1;
4944 #if defined(SOLARIS)
4945  struct statvfs buf;
4946 #else /* SOLARIS */
4947  struct statfs buf;
4948 #endif /* SOLARIS */
4949 
4950 #if defined(SOLARIS)
4951  if (statvfs (path_p, &buf) == -1)
4952 #elif defined(AIX)
4953  if (statfs ((char *) path_p, &buf) == -1)
4954 #else /* AIX */
4955  if (statfs (path_p, &buf) == -1)
4956 #endif /* AIX */
4957  {
4958  if (errno == ENOENT
4960  {
4961  /* The given file did not exist. We create it for temporary consumption then it is removed */
4962  npages_of_partition = fileio_get_number_of_partition_free_pages (path_p, page_size);
4963 
4964  /* Close the file and remove it */
4965  fileio_close (vol_fd);
4966  (void) remove (path_p);
4967  }
4968  else
4969  {
4971  }
4972  }
4973  else
4974  {
4975  const size_t f_avail_size = buf.f_bsize * buf.f_bavail;
4976  npages_of_partition = f_avail_size / page_size;
4977  if (npages_of_partition < 0 || npages_of_partition > INT_MAX)
4978  {
4979  npages_of_partition = INT_MAX;
4980  }
4981  }
4982 
4983  if (npages_of_partition < 0)
4984  {
4985  return -1;
4986  }
4987  else
4988  {
4989  assert (npages_of_partition <= INT_MAX);
4990 
4991  return (int) npages_of_partition;
4992  }
4993 #endif /* WINDOWS */
4994 }
4995 
4996 /*
4997  * fileio_get_number_of_partition_free_pages () - document me!
4998  *
4999  * return : Number of free sectors
5000  * path_p (in) : Path to disk partition
5001  */
5002 DKNSECTS
5004 {
5005 #if defined(WINDOWS)
5006  return (DKNSECTS) free_space (path_p, IO_SECTORSIZE);
5007 #else /* WINDOWS */
5008  int vol_fd;
5009  INT64 nsectors_of_partition = -1;
5010 #if defined(SOLARIS)
5011  struct statvfs buf;
5012 #else /* SOLARIS */
5013  struct statfs buf;
5014 #endif /* SOLARIS */
5015 
5016 #if defined(SOLARIS)
5017  if (statvfs (path_p, &buf) == -1)
5018 #elif defined(AIX)
5019  if (statfs ((char *) path_p, &buf) == -1)
5020 #else /* AIX */
5021  if (statfs (path_p, &buf) == -1)
5022 #endif /* AIX */
5023  {
5024  if (errno == ENOENT
5026  {
5027  /* The given file did not exist. We create it for temporary consumption then it is removed */
5028  nsectors_of_partition = fileio_get_number_of_partition_free_sectors (path_p);
5029 
5030  /* Close the file and remove it */
5031  fileio_close (vol_fd);
5032  (void) remove (path_p);
5033  }
5034  else
5035  {
5037  }
5038  }
5039  else
5040  {
5041  const size_t f_avail_size = buf.f_bsize * buf.f_bavail;
5042  nsectors_of_partition = f_avail_size / IO_SECTORSIZE;
5043  if (nsectors_of_partition < 0 || nsectors_of_partition > INT_MAX)
5044  {
5045  nsectors_of_partition = INT_MAX;
5046  }
5047  }
5048 
5049  if (nsectors_of_partition < 0)
5050  {
5051  return -1;
5052  }
5053  else
5054  {
5055  assert (nsectors_of_partition <= INT_MAX);
5056 
5057  return (DKNSECTS) nsectors_of_partition;
5058  }
5059 #endif /* WINDOWS */
5060 }
5061 
5062 /*
5063  * fileio_rename () - Rename the volume from "old_vlabel" to "new_vlabel"
5064  * return: new_vlabel or NULL in case of error
5065  * volid(in): Volume Identifier
5066  * old_vlabel(in): Old volume label
5067  * new_vlabel(in): New volume label
5068  */
5069 const char *
5070 fileio_rename (VOLID vol_id, const char *old_label_p, const char *new_label_p)
5071 {
5072 #if defined(CUBRID_DEBUG)
5073  if (fileio_get_volume_descriptor (vol_id) != NULL_VOLDES)
5074  {
5075  er_log_debug (ARG_FILE_LINE, "io_rename: SYSTEM ERROR..The volume %s must be dismounted to rename a volume...");
5076  return NULL;
5077  }
5078 #endif /* CUBRID_DEBUG */
5079 
5080  if (os_rename_file (old_label_p, new_label_p) != NO_ERROR)
5081  {
5082  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_RENAME_FAIL, 2, old_label_p, new_label_p);
5083  return NULL;
5084  }
5085  return new_label_p;
5086 }
5087 
5088 /*
5089  * fileio_is_volume_exist () - Find if a volume exist
5090  * return: true/false
5091  * vlabel(in): Volume label
5092  */
5093 bool
5094 fileio_is_volume_exist (const char *vol_label_p)
5095 {
5096  int vol_fd;
5097 
5098 #if !defined(CS_MODE)
5099  /* Is volume already mounted ? */
5100  vol_fd = fileio_find_volume_descriptor_with_label (vol_label_p);
5101  if (vol_fd != NULL_VOLDES)
5102  {
5103  return true;
5104  }
5105 #endif /* !CS_MODE */
5106 
5107  /* Check the existance of the file by opening the file */
5108  vol_fd = fileio_open (vol_label_p, O_RDONLY, 0);
5109  if (vol_fd == NULL_VOLDES)
5110  {
5111  if (errno == ENOENT)
5112  {
5113  return false;
5114  }
5115  }
5116  else
5117  {
5118  fileio_close (vol_fd);
5119  }
5120 
5121  return true;
5122 }
5123 
5124 /*
5125  * fileio_is_volume_exist_and_file () - Find if a volume exist and is a regular file
5126  * return: true/false
5127  * vlabel(in): Volume label
5128  *
5129  * Note: This is to differentiate between directories, raw devices, and files.
5130  */
5131 bool
5132 fileio_is_volume_exist_and_file (const char *vol_label_p)
5133 {
5134  int vol_fd;
5135  struct stat stbuf;
5136 
5137  /* Is volume already mounted ? */
5138  vol_fd = fileio_find_volume_descriptor_with_label (vol_label_p);
5139  if (vol_fd != NULL_VOLDES)
5140  {
5141  return true;
5142  }
5143 
5144  if (stat (vol_label_p, &stbuf) != -1 && S_ISREG (stbuf.st_mode))
5145  {
5146  return true;
5147  }
5148 
5149  return false;
5150 }
5151 
5152 static char *
5153 fileio_check_file_exist (char *name_p, char *new_guess_path_p, int check_size, int *max_name_size_p)
5154 {
5155  char *tmp_name_p;
5156  int vol_fd = NULL_VOLDES;
5157 
5158  tmp_name_p = name_p - (*max_name_size_p - check_size + 1);
5159  *tmp_name_p = '\0';
5160 
5161  vol_fd = fileio_open (new_guess_path_p, O_RDONLY, 0);
5162  if (vol_fd == NULL_VOLDES)
5163  {
5164  vol_fd = fileio_open (new_guess_path_p, FILEIO_DISK_FORMAT_MODE, FILEIO_DISK_PROTECTION_MODE);
5165  if (vol_fd == NULL_VOLDES && errno == ENAMETOOLONG)
5166  {
5167  *max_name_size_p = check_size + 1;
5168  name_p = tmp_name_p;
5169  }
5170  else
5171  {
5172  if (vol_fd != NULL_VOLDES)
5173  {
5174  fileio_close (vol_fd);
5175  (void) remove (new_guess_path_p);
5176  }
5177  *tmp_name_p = 'x';
5178  }
5179  }
5180  else
5181  {
5182  *tmp_name_p = 'x';
5183  if (vol_fd != NULL_VOLDES)
5184  {
5185  fileio_close (vol_fd);
5186  }
5187  }
5188 
5189  return name_p;
5190 }
5191 
5192 static char *
5193 fileio_check_file_is_same (char *name_p, char *new_guess_path_p, int check_size, int *max_name_size_p, struct stat *buf)
5194 {
5195  char *tmp_name_p;
5196 
5197  tmp_name_p = name_p - (*max_name_size_p - check_size + 1);
5198  *tmp_name_p = '\0';
5199 
5200  if (stat (new_guess_path_p, &buf[1]) == 0 && buf[0].st_ino == buf[1].st_ino)
5201  {
5202  *max_name_size_p = check_size + 1;
5203  name_p = tmp_name_p;
5204  }
5205  else
5206  {
5207  *tmp_name_p = 'x';
5208  }
5209 
5210  return name_p;
5211 }
5212 
5213 /*
5214  * fileio_get_primitive_way_max () - Find the longest names of files and
5215  * path names that can be given for
5216  * the given file system (path) in a
5217  * primitive way
5218  * return: filename max
5219  * path(in): Path to directory or file name
5220  * filename_max(out): the longest name that could be given
5221  * pathname_max(out): the longest path that could be given
5222  *
5223  * Note: This function should only be used when the values cannot be
5224  * determine using pathconf.
5225  */
5226 static int
5227 fileio_get_primitive_way_max (const char *path_p, long int *file_name_max_p, long int *path_name_max_p)
5228 {
5229  static char last_guess_path[PATH_MAX] = { '\0' };
5230  static int max_name_size = -1;
5231  char new_guess_path[PATH_MAX];
5232  char *name_p;
5233  int check256, check14;
5234  bool is_remove = false;
5235  int vol_fd = NULL_VOLDES;
5236  struct stat buf[2];
5237  int i;
5238  int success;
5239 
5240  *file_name_max_p = NAME_MAX;
5241  *path_name_max_p = PATH_MAX;
5242 
5243  if (*file_name_max_p > *path_name_max_p)
5244  {
5245  *file_name_max_p = *path_name_max_p;
5246  }
5247 
5248  /* Verify the above compilation guesses */
5249 
5250  strncpy_bufsize (new_guess_path, path_p);
5251  name_p = strrchr (new_guess_path, '/');
5252 #if defined(WINDOWS)
5253  {
5254  char *tmp_name = strrchr (new_guess_path, '\\');
5255  if (name_p < tmp_name)
5256  name_p = tmp_name;
5257  }
5258 #endif /* WINDOWS */
5259 
5260  if (name_p != NULL)
5261  {
5262  *++name_p = '\0';
5263  }
5264  else
5265  {
5266  name_p = new_guess_path;
5267  }
5268 
5269  if (max_name_size != -1 && strcmp (last_guess_path, new_guess_path) == 0)
5270  {
5271  return *file_name_max_p = max_name_size;
5272  }
5273 
5274  for (max_name_size = 1, i = (int) strlen (new_guess_path) + 1;
5275  max_name_size < *file_name_max_p && i < *path_name_max_p; max_name_size++, i++)
5276  {
5277  *name_p++ = 'x';
5278  }
5279 
5280  *name_p++ = '\0';
5281 
5282  /* Start from the back until you find a file which is different. The assumption is that the files do not exist. */
5283 
5284  check256 = 1;
5285  check14 = 1;
5286  while (max_name_size > 1)
5287  {
5288  vol_fd = fileio_open (new_guess_path, O_RDONLY, 0);
5289  if (vol_fd != NULL_VOLDES)
5290  {
5291  /* The file already exist */
5292  is_remove = false;
5293  break;
5294  }
5295  else
5296  {
5297  /* The file did not exist. Create the file and at the end remove the file */
5298  is_remove = true;
5300  if (vol_fd != NULL_VOLDES)
5301  {
5302  break;
5303  }
5304 
5305  if (errno != ENAMETOOLONG)
5306  {
5307  goto error;
5308  }
5309 
5310  /*
5311  * Name truncation is not allowed. Most Unix systems accept
5312  * filename of 256 or 14.
5313  * Assume one of this for now
5314  */
5315  if (max_name_size > 257 && check256 == 1)
5316  {
5317  check256 = 0;
5318  name_p = fileio_check_file_exist (name_p, new_guess_path, 256, &max_name_size);
5319  }
5320  else if (max_name_size > 15 && check14 == 1)
5321  {
5322  check14 = 0;
5323  name_p = fileio_check_file_exist (name_p, new_guess_path, 14, &max_name_size);
5324  }
5325  *name_p-- = '\0';
5326  max_name_size--;
5327  }
5328  }
5329 
5330  strncpy (last_guess_path, new_guess_path, PATH_MAX);
5331 
5332  if (vol_fd != NULL_VOLDES)
5333  {
5334  fileio_close (vol_fd);
5335  if (stat (new_guess_path, &buf[0]) == -1)
5336  {
5337  goto error;
5338  }
5339  }
5340  else
5341  {
5342  goto error;
5343  }
5344 
5345  /*
5346  * Most Unix system are either 256 or 14. Do a quick check to see if 15
5347  * is the same than current value. If it is, set maxname to 15 and decrement
5348  * name.
5349  */
5350 
5351  check256 = 1;
5352  check14 = 1;
5353  for (; max_name_size > 1; max_name_size--)
5354  {
5355  *name_p-- = '\0';
5356  if ((success = stat (new_guess_path, &buf[1])) == 0 && buf[0].st_ino == buf[1].st_ino)
5357  {
5358  /*
5359  * Same file. Most Unix system allow either 256 or 14 for filenames.
5360  * Perform a quick check to see if we can speed up the checking
5361  * process
5362  */
5363 
5364  if (max_name_size > 257 && check256 == 1)
5365  {
5366  check256 = 0;
5367  name_p = fileio_check_file_is_same (name_p, new_guess_path, 256, &max_name_size, buf);
5368  /* Check if the name with 257 is the same. If it is advance the to 256 */
5369  }
5370  else if (max_name_size > 15 && check14 == 1)
5371  {
5372  check14 = 0;
5373  name_p = fileio_check_file_is_same (name_p, new_guess_path, 14, &max_name_size, buf);
5374  }
5375  }
5376  else
5377  {
5378  if (success == 0)
5379  {
5380  continue;
5381  }
5382  else if (errno == ENOENT)
5383  {
5384  /* The file did not exist or the file is different. Therefore, previous maxname is the maximum name */
5385  max_name_size++;
5386  break;
5387  }
5388 
5389  goto error;
5390  }
5391  }
5392 
5393  /* The length has been found */
5394  if (is_remove == true)
5395  {
5396  (void) remove (last_guess_path);
5397  }
5398 
5399  name_p = strrchr (last_guess_path, '/');
5400 #if defined(WINDOWS)
5401  {
5402  char *tmp_name = strrchr (last_guess_path, '\\');
5403  if (name_p < tmp_name)
5404  {
5405  name_p = tmp_name;
5406  }
5407  }
5408 #endif /* WINDOWS */
5409  if (name_p != NULL)
5410  {
5411  *++name_p = '\0';
5412  }
5413 
5414  /* Plus 2 since we start with zero and we need to include null character */
5415  max_name_size = max_name_size + 2;
5416 
5417  return *file_name_max_p = max_name_size;
5418 
5419 error:
5420  if (is_remove == true)
5421  {
5422  (void) remove (last_guess_path);
5423  }
5424 
5425  max_name_size = -1;
5426  *path_name_max_p = -1;
5427  *file_name_max_p = -1;
5428 
5429  return -1;
5430 }
5431 
5432 /*
5433  * fileio_get_max_name () - Find the longest names of files and path
5434  * names that can be given for the given file
5435  * system (path)
5436  * return: filename max
5437  * path(in): Path to directory or file name
5438  * filename_max(out): the longest name that could be given
5439  * pathname_max(out): the longest path that could be given
5440  *
5441  * Note: The main goal of this function is to respect the limits that
5442  * the database system is using at compile time (e.g., variables
5443  * defined with PATH_MAX) and at run time. For example, if
5444  * the constant FILENAME_MAX cannot be used to detect long names
5445  * since this value at compilation time may be different from the
5446  * value at execution time (e.g., at other installation). If we
5447  * use the compiled value, it may be possible that we will be
5448  * removing a file when a new one is created when truncation of
5449  * filenames is allowed at the running file system.
5450  * In addition, it is possible that such limits may differ across
5451  * file systems, device boundaries. For example, Unix System V
5452  * uses a maximum of 14 characters for file names, and Unix BSD
5453  * uses 255. On this implementations, we are forced to use 14
5454  * characters.
5455  * The functions returns the minimum of the compilation and run
5456  * time for both filename and pathname.
5457  */
5458 int
5459 fileio_get_max_name (const char *given_path_p, long int *file_name_max_p, long int *path_name_max_p)
5460 {
5461  char new_path[PATH_MAX];
5462  const char *path_p;
5463  char *name_p;
5464  struct stat stbuf;
5465 
5466  /* Errno need to be reset to find out if the values are not handle */
5467  errno = 0;
5468  path_p = given_path_p;
5469 
5470  *file_name_max_p = pathconf ((char *) path_p, _PC_NAME_MAX);
5471  *path_name_max_p = pathconf ((char *) path_p, _PC_PATH_MAX);
5472 
5473  if ((*file_name_max_p < 0 || *path_name_max_p < 0) && (errno == ENOENT || errno == EINVAL))
5474  {
5475  /*
5476  * The above values may not be accepted for that path. The path may be
5477  * a file instead of a directory, try it with the directory since some
5478  * implementations cannot answer the above question when the path is a
5479  * file
5480  */
5481 
5482  if (stat (path_p, &stbuf) != -1 && ((stbuf.st_mode & S_IFMT) != S_IFDIR))
5483  {
5484  /* Try it with the directory instead */
5485  strncpy_bufsize (new_path, given_path_p);
5486  name_p = strrchr (new_path, '/');
5487 #if defined(WINDOWS)
5488  {
5489  char *tmp_name = strrchr (new_path, '\\');
5490  if (name_p < tmp_name)
5491  name_p = tmp_name;
5492  }
5493 #endif /* WINDOWS */
5494  if (name_p != NULL)
5495  {
5496  *name_p = '\0';
5497  }
5498  path_p = new_path;
5499 
5500  *file_name_max_p = pathconf ((char *) path_p, _PC_NAME_MAX);
5501  *path_name_max_p = pathconf ((char *) path_p, _PC_PATH_MAX);
5502 
5503  path_p = given_path_p;
5504  }
5505  }
5506 
5507  if (*file_name_max_p < 0 || *path_name_max_p < 0)
5508  {
5509  /* If errno is zero, the values are indeterminate */
5510  (void) fileio_get_primitive_way_max (path_p, file_name_max_p, path_name_max_p);
5511  }
5512 
5513  /* Make sure that we do not overpass compilation structures */
5514  if (*file_name_max_p < 0 || *file_name_max_p > NAME_MAX)
5515  {
5516  *file_name_max_p = NAME_MAX;
5517  }
5518 
5519  if (*path_name_max_p < 0 || *path_name_max_p > PATH_MAX)
5520  {
5521  *path_name_max_p = PATH_MAX;
5522  }
5523 
5524  return *file_name_max_p;
5525 }
5526 
5527 /*
5528  * fileio_get_base_file_name () - Find start of basename in given filename
5529  * return: basename
5530  * fullname(in): Fullname of file
5531  */
5532 const char *
5533 fileio_get_base_file_name (const char *full_name_p)
5534 {
5535  const char *no_path_name_p;
5536 
5537  no_path_name_p = strrchr (full_name_p, PATH_SEPARATOR);
5538 #if defined(WINDOWS)
5539  {
5540  const char *nn_tmp = strrchr (full_name_p, '/');
5541  if (no_path_name_p < nn_tmp)
5542  {
5543  no_path_name_p = nn_tmp;
5544  }
5545  }
5546 #endif /* WINDOWS */
5547  if (no_path_name_p == NULL)
5548  {
5549  no_path_name_p = full_name_p;
5550  }
5551  else
5552  {
5553  no_path_name_p++; /* Skip to the name */
5554  }
5555 
5556  return no_path_name_p;
5557 }
5558 
5559 /*
5560  * fileio_get_directory_path () - Find directory path of given file. That is copy all but the
5561  * basename of filename
5562  * return: path
5563  * path(out): The path of the file
5564  * fullname(in): Fullname of file
5565  */
5566 char *
5567 fileio_get_directory_path (char *path_p, const char *full_name_p)
5568 {
5569  const char *base_p;
5570  size_t path_size;
5571 
5572  base_p = fileio_get_base_file_name (full_name_p);
5573 
5574  assert (base_p >= full_name_p);
5575 
5576  if (base_p == full_name_p)
5577  {
5578  /* Same pointer, the file does not contain a path/directory portion. Use the current directory */
5579  if (getcwd (path_p, PATH_MAX) == NULL)
5580  {
5582  *path_p = '\0';
5583  }
5584  }
5585  else
5586  {
5587  path_size = (size_t) (base_p - full_name_p - 1);
5588  if (path_size > PATH_MAX)
5589  {
5590  path_size = PATH_MAX;
5591  }
5592  memcpy (path_p, full_name_p, path_size);
5593  path_p[path_size] = '\0';
5594  }
5595 
5596  return path_p;
5597 }
5598 
5599 /*
5600  * fileio_get_volume_max_suffix () -
5601  * return:
5602  */
5603 int
5605 {
5606  return FILEIO_MAX_SUFFIX_LENGTH;
5607 }
5608 
5609 /*
5610  * fileio_make_volume_lock_name () - Build the name of volumes
5611  * return: void
5612  * vol_lockname(out):
5613  * vol_fullname(in):
5614  *
5615  * Note: The caller must have enough space to store the name of the volume
5616  * that is constructed(sprintf). It is recommended to have at least
5617  * DB_MAX_PATH_LENGTH length.
5618  */
5619 static void
5620 fileio_make_volume_lock_name (char *vol_lock_name_p, const char *vol_full_name_p)
5621 {
5622  sprintf (vol_lock_name_p, "%s%s", vol_full_name_p, FILEIO_VOLLOCK_SUFFIX);
5623 }
5624 
5625 /*
5626  * fileio_make_volume_info_name () - Build the name of volumes
5627  * return: void
5628  * volinfo_name(out):
5629  * db_fullname(in):
5630  *
5631  * Note: The caller must have enough space to store the name of the volume
5632  * that is constructed(sprintf). It is recommended to have at least
5633  * DB_MAX_PATH_LENGTH length.
5634  */
5635 void
5636 fileio_make_volume_info_name (char *vol_info_name_p, const char *db_full_name_p)
5637 {
5638  sprintf (vol_info_name_p, "%s%s", db_full_name_p, FILEIO_VOLINFO_SUFFIX);
5639 }
5640 
5641 /*
5642  * fileio_make_volume_ext_name () - Build the name of volumes
5643  * return: void
5644  * volext_fullname(out):
5645  * ext_path(in):
5646  * ext_name(in):
5647  * volid(in):
5648  *
5649  * Note: The caller must have enough space to store the name of the volume
5650  * that is constructed(sprintf). It is recommended to have at least
5651  * DB_MAX_PATH_LENGTH length.
5652  */
5653 void
5654 fileio_make_volume_ext_name (char *vol_ext_full_name_p, const char *ext_path_p, const char *ext_name_p, VOLID vol_id)
5655 {
5656  sprintf (vol_ext_full_name_p, "%s%s%s%s%03d", ext_path_p, FILEIO_PATH_SEPARATOR (ext_path_p), ext_name_p,
5657  FILEIO_VOLEXT_PREFIX, vol_id);
5658 }
5659 
5660 /*
5661  * fileio_make_volume_ext_given_name () - Build the name of volumes
5662  * return: void
5663  * volext_fullname(out):
5664  * ext_path(in):
5665  * ext_name(in):
5666  *
5667  * Note: The caller must have enough space to store the name of the volume
5668  * that is constructed(sprintf). It is recommended to have at least
5669  * DB_MAX_PATH_LENGTH length.
5670  */
5671 void
5672 fileio_make_volume_ext_given_name (char *vol_ext_full_name_p, const char *ext_path_p, const char *ext_name_p)
5673 {
5674  sprintf (vol_ext_full_name_p, "%s%s%s", ext_path_p, FILEIO_PATH_SEPARATOR (ext_path_p), ext_name_p);
5675 }
5676 
5677 /*
5678  * fileio_make_volume_temp_name () - Build the name of volumes
5679  * return: void
5680  * voltmp_fullname(out):
5681  * tmp_path(in):
5682  * tmp_name(in):
5683  * volid(in):
5684  *
5685  * Note: The caller must have enough space to store the name of the volume
5686  * that is constructed(sprintf). It is recommended to have at least
5687  * DB_MAX_PATH_LENGTH length.
5688  */
5689 void
5690 fileio_make_volume_temp_name (char *vol_tmp_full_name_p, const char *tmp_path_p, const char *tmp_name_p, VOLID vol_id)
5691 {
5692  sprintf (vol_tmp_full_name_p, "%s%c%s%s%03d", tmp_path_p, PATH_SEPARATOR, tmp_name_p, FILEIO_VOLTMP_PREFIX, vol_id);
5693 }
5694 
5695 /*
5696  * fileio_make_log_active_name () - Build the name of volumes
5697  * return: void
5698  * logactive_name(out):
5699  * log_path(in):
5700  * dbname(in):
5701  *
5702  * Note: The caller must have enough space to store the name of the volume
5703  * that is constructed(sprintf). It is recommended to have at least
5704  * DB_MAX_PATH_LENGTH length.
5705  */
5706 void
5707 fileio_make_log_active_name (char *log_active_name_p, const char *log_path_p, const char *db_name_p)
5708 {
5709  sprintf (log_active_name_p, "%s%s%s%s", log_path_p, FILEIO_PATH_SEPARATOR (log_path_p), db_name_p,
5711 
5712 }
5713 
5714 /*
5715  * fileio_make_temp_log_files_from_backup () - Build the name of volumes
5716  * return: void
5717  * logactive_name(out):
5718  * level(in):
5719  * active_name(in):
5720  *
5721  * Note: The caller must have enough space to store the name of the volume
5722  * that is constructed(sprintf). It is recommended to have at least
5723  * DB_MAX_PATH_LENGTH length.
5724  */
5725 void
5727  const char *base_log_name)
5728 {
5729  switch (to_volid)
5730  {
5732  sprintf (temp_log_name, "%s_%03d_tmp", base_log_name, level);
5733  break;
5734  case LOG_DBLOG_INFO_VOLID:
5735  sprintf (temp_log_name, "%s_%03d_tmp", base_log_name, level);
5736  break;
5738  sprintf (temp_log_name, "%s_%03d_tmp", base_log_name, level);
5739  break;
5740  default:
5741  break;
5742  }
5743 }
5744 
5745 /*
5746  * fileio_make_log_archive_name () - Build the name of volumes
5747  * return: void
5748  * logarchive_name(out):
5749  * log_path(in):
5750  * dbname(in):
5751  * arvnum(in):
5752  *
5753  * Note: The caller must have enough space to store the name of the volume
5754  * that is constructed(sprintf). It is recommended to have at least
5755  * DB_MAX_PATH_LENGTH length.
5756  */
5757 void
5758 fileio_make_log_archive_name (char *log_archive_name_p, const char *log_path_p, const char *db_name_p,
5759  int archive_number)
5760 {
5761  sprintf (log_archive_name_p, "%s%s%s%s%03d", log_path_p, FILEIO_PATH_SEPARATOR (log_path_p), db_name_p,
5762  FILEIO_SUFFIX_LOGARCHIVE, archive_number);
5763 }
5764 
5765 /*
5766  * fileio_make_removed_log_archive_name () - Build the name of removed volumes
5767  * return: void
5768  * logarchive_name(out):
5769  * log_path(in):
5770  * dbname(in):
5771  *
5772  * Note: The caller must have enough space to store the name of the volume
5773  * that is constructed(sprintf). It is recommended to have at least
5774  * DB_MAX_PATH_LENGTH length.
5775  */
5776 void
5777 fileio_make_removed_log_archive_name (char *log_archive_name_p, const char *log_path_p, const char *db_name_p)
5778 {
5779  sprintf (log_archive_name_p, "%s%s%s%s.removed", log_path_p, FILEIO_PATH_SEPARATOR (log_path_p), db_name_p,
5781 }
5782 
5783 /*
5784  * fileio_make_log_archive_temp_name () -
5785  * return: void
5786  * logarchive_name_p(out):
5787  * log_path_p(in):
5788  * db_name_p(in):
5789  *
5790  * Note:
5791  */
5792 void
5793 fileio_make_log_archive_temp_name (char *log_archive_temp_name_p, const char *log_path_p, const char *db_name_p)
5794 {
5795  const char *fmt_string_p;
5796 
5797  fmt_string_p = "%s%s%s%s";
5798 
5799  snprintf (log_archive_temp_name_p, PATH_MAX - 1, fmt_string_p, log_path_p, FILEIO_PATH_SEPARATOR (log_path_p),
5800  db_name_p, FILEIO_SUFFIX_TMP_LOGARCHIVE);
5801 }
5802 
5803 /*
5804  * fileio_make_log_info_name () - Build the name of volumes
5805  * return: void
5806  * loginfo_name(out):
5807  * log_path(in):
5808  * dbname(in):
5809  *
5810  * Note: The caller must have enough space to store the name of the volume
5811  * that is constructed(sprintf). It is recommended to have at least
5812  * DB_MAX_PATH_LENGTH length.
5813  */
5814 void
5815 fileio_make_log_info_name (char *log_info_name_p, const char *log_path_p, const char *db_name_p)
5816 {
5817  sprintf (log_info_name_p, "%s%s%s%s", log_path_p, FILEIO_PATH_SEPARATOR (log_path_p), db_name_p,
5819 }
5820 
5821 /*
5822  * fileio_make_backup_volume_info_name () - Build the name of volumes
5823  * return: void
5824  * backup_volinfo_name(out):
5825  * backinfo_path(in):
5826  * dbname(in):
5827  *
5828  * Note: The caller must have enough space to store the name of the volume
5829  * that is constructed(sprintf). It is recommended to have at least
5830  * DB_MAX_PATH_LENGTH length.
5831  */
5832 void
5833 fileio_make_backup_volume_info_name (char *backup_volinfo_name_p, const char *backup_info_path_p, const char *db_name_p)
5834 {
5835  sprintf (backup_volinfo_name_p, "%s%s%s%s", backup_info_path_p, FILEIO_PATH_SEPARATOR (backup_info_path_p), db_name_p,
5837 }
5838 
5839 /*
5840  * fileio_make_backup_name () - Build the name of volumes
5841  * return: void
5842  * backup_name(out):
5843  * nopath_volname(in):
5844  * backup_path(in):
5845  * level(in):
5846  * unit_num(in):
5847  *
5848  * Note: The caller must have enough space to store the name of the volume
5849  * that is constructed(sprintf). It is recommended to have at least
5850  * DB_MAX_PATH_LENGTH length.
5851  */
5852 void
5853 fileio_make_backup_name (char *backup_name_p, const char *no_path_vol_name_p, const char *backup_path_p,
5854  FILEIO_BACKUP_LEVEL level, int unit_num)
5855 {
5856  if (unit_num >= 0)
5857  {
5858  sprintf (backup_name_p, "%s%c%s%s%dv%03d", backup_path_p, PATH_SEPARATOR, no_path_vol_name_p,
5859  FILEIO_SUFFIX_BACKUP, level, unit_num);
5860  }
5861  else
5862  {
5863  /* without unit number, usually with FILEIO_NO_BACKUP_UNITS */
5864  sprintf (backup_name_p, "%s%c%s%s%d", backup_path_p, PATH_SEPARATOR, no_path_vol_name_p, FILEIO_SUFFIX_BACKUP,
5865  level);
5866  }
5867 }
5868 
5869 /*
5870  * fileio_make_dwb_name () - Build the name of DWB volume
5871  * return: void
5872  * dwb_name_p(out): the name of DWB volume
5873  * dwb_path_p(in): double write buffer path
5874  * dbname(in): database name
5875  *
5876  * Note: The caller must have enough space to store the name of the volume
5877  * that is constructed(sprintf). It is recommended to have at least
5878  * DB_MAX_PATH_LENGTH length.
5879  */
5880 void
5881 fileio_make_dwb_name (char *dwb_name_p, const char *dwb_path_p, const char *db_name_p)
5882 {
5883  sprintf (dwb_name_p, "%s%s%s%s", dwb_path_p, FILEIO_PATH_SEPARATOR (dwb_path_p), db_name_p, FILEIO_SUFFIX_DWB);
5884 }
5885 
5886 /*
5887  * fileio_make_keys_name () - Build the name of KEYS file (for TDE Master Key)
5888  * return: void
5889  * keys_name_p(out): the name of KEYS file
5890  * db_full_name_p(in): database full path
5891  *
5892  * Note: The caller must have enough space to store the name of the volume
5893  * that is constructed(sprintf). It is recommended to have at least
5894  * DB_MAX_PATH_LENGTH length.
5895  */
5896 void
5897 fileio_make_keys_name (char *keys_name_p, const char *db_full_name_p)
5898 {
5899  sprintf (keys_name_p, "%s%s", db_full_name_p, FILEIO_SUFFIX_KEYS);
5900 }
5901 
5902 /*
5903  * fileio_make_keys_name_given_path () - Build the name of KEYS file (for TDE Master Key)
5904  * return: void
5905  * keys_name_p(out): the bname of KEYS file
5906  * keys_path_p(in): the directory path of KEYS file
5907  * db_name_p(in): database name
5908  *
5909  * Note: The caller must have enough space to store the name of the volume
5910  * that is constructed(sprintf). It is recommended to have at least
5911  * DB_MAX_PATH_LENGTH length.
5912  */
5913 void
5914 fileio_make_keys_name_given_path (char *keys_name_p, const char *keys_path_p, const char *db_name_p)
5915 {
5916  sprintf (keys_name_p, "%s%s%s%s", keys_path_p, FILEIO_PATH_SEPARATOR (keys_path_p), db_name_p, FILEIO_SUFFIX_KEYS);
5917 }
5918 
5919 #ifdef UNSTABLE_TDE_FOR_REPLICATION_LOG
5920 /*
5921  * fileio_make_ha_sock_name () - Build the name of HA socket name (for sharing TDE Data keys)
5922  * return: void
5923  * keys_name_p(out): the name of KEYS volume
5924  * dbname(in): database name
5925  *
5926  * Note: The caller must have enough space to store the name of the volume
5927  * that is constructed(sprintf). It is recommended to have at least
5928  * DB_MAX_PATH_LENGTH length.
5929  */
5930 void
5931 fileio_make_ha_sock_name (char *sock_path_p, const char *base_path_p, const char *sock_name_p)
5932 {
5933  sprintf (sock_path_p, "%s%s%s", base_path_p, FILEIO_PATH_SEPARATOR (base_path_p), sock_name_p);
5934 }
5935 #endif /* UNSTABLE_TDE_FOR_REPLICATION_LOG */
5936 
5937 /*
5938  * fileio_cache () - Cache information related to a mounted volume
5939  * return: vdes on success, NULL_VOLDES on failure
5940  * volid(in): Permanent volume identifier
5941  * vlabel(in): Name/label of the volume
5942  * vdes(in): I/O volume descriptor
5943  * lockf_type(in): Type of lock
5944  */
5945 static int
5946 fileio_cache (VOLID vol_id, const char *vol_label_p, int vol_fd, FILEIO_LOCKF_TYPE lockf_type)
5947 {
5948  bool is_permanent_volume;
5949  FILEIO_VOLUME_INFO *vol_info_p;
5950  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
5951  int i, j, rv;
5952 
5954 
5955  if (vol_id > NULL_VOLID)
5956  {
5957  /* perm volume */
5958  if (vol_id < fileio_Vol_info_header.next_temp_volid)
5959  {
5960  i = vol_id / FILEIO_VOLINFO_INCREMENT;
5961  j = vol_id % FILEIO_VOLINFO_INCREMENT;
5962  if (vol_id >= fileio_Vol_info_header.max_perm_vols
5963  && fileio_expand_permanent_volume_info (&fileio_Vol_info_header, vol_id) < 0)
5964  {
5965  return NULL_VOLDES;
5966  }
5967  is_permanent_volume = true;
5968  }
5969  else
5970  {
5971  /* volid is the next temp volume id */
5972  i = (fileio_Vol_info_header.num_volinfo_array - 1 - (LOG_MAX_DBVOLID - vol_id) / FILEIO_VOLINFO_INCREMENT);
5974  if (((LOG_MAX_DBVOLID - vol_id) >= fileio_Vol_info_header.max_temp_vols)
5975  && fileio_expand_temporary_volume_info (&fileio_Vol_info_header, vol_id) < 0)
5976  {
5977  return NULL_VOLDES;
5978  }
5979  is_permanent_volume = false;
5980  }
5981 
5982  vol_info_p = &fileio_Vol_info_header.volinfo[i][j];
5983  vol_info_p->volid = vol_id;
5984  vol_info_p->vdes = vol_fd;
5985  vol_info_p->lockf_type = lockf_type;
5986  strncpy (vol_info_p->vlabel, vol_label_p, PATH_MAX);
5987  /* modify next volume id */
5988  rv = pthread_mutex_lock (&fileio_Vol_info_header.mutex);
5989  if (is_permanent_volume)
5990  {
5991  if (fileio_Vol_info_header.next_perm_volid <= vol_id)
5992  {
5993  fileio_Vol_info_header.next_perm_volid = vol_id + 1;
5994  }
5995  }
5996  else
5997  {
5998  if (fileio_Vol_info_header.next_temp_volid >= vol_id)
5999  {
6000  fileio_Vol_info_header.next_temp_volid = vol_id - 1;
6001  }
6002  }
6003  pthread_mutex_unlock (&fileio_Vol_info_header.mutex);
6004  }
6005  else
6006  {
6007  if (vol_id == LOG_DBDWB_VOLID)
6008  {
6009  /* Do not cache DWB. */
6010  return vol_fd;
6011  }
6012 
6013  /* system volume */
6014  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
6015  if (fileio_Sys_vol_info_header.anchor.vdes != NULL_VOLDES)
6016  {
6017  sys_vol_info_p = (FILEIO_SYSTEM_VOLUME_INFO *) malloc (sizeof (FILEIO_SYSTEM_VOLUME_INFO));
6018  if (sys_vol_info_p == NULL)
6019  {
6021  sizeof (FILEIO_SYSTEM_VOLUME_INFO));
6022  vol_fd = NULL_VOLDES;
6023  }
6024  else
6025  {
6026  sys_vol_info_p->volid = vol_id;
6027  sys_vol_info_p->vdes = vol_fd;
6028  sys_vol_info_p->lockf_type = lockf_type;
6029  strncpy_bufsize (sys_vol_info_p->vlabel, vol_label_p);
6030  sys_vol_info_p->next = fileio_Sys_vol_info_header.anchor.next;
6031  fileio_Sys_vol_info_header.anchor.next = sys_vol_info_p;
6032  fileio_Sys_vol_info_header.num_vols++;
6033 #if defined(WINDOWS)
6034  pthread_mutex_init (&sys_vol_info_p->sysvol_mutex, NULL);
6035 #endif /* WINDOWS */
6036  }
6037  }
6038  else
6039  {
6040  sys_vol_info_p = &fileio_Sys_vol_info_header.anchor;
6041  sys_vol_info_p->volid = vol_id;
6042  sys_vol_info_p->vdes = vol_fd;
6043  sys_vol_info_p->lockf_type = lockf_type;
6044  sys_vol_info_p->next = NULL;
6045  strncpy_bufsize (sys_vol_info_p->vlabel, vol_label_p);
6046 #if defined(WINDOWS)
6047  pthread_mutex_init (&sys_vol_info_p->sysvol_mutex, NULL);
6048 #endif /* WINDOWS */
6049  fileio_Sys_vol_info_header.num_vols++;
6050  }
6051 
6052  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6053  }
6054 
6055  return vol_fd;
6056 }
6057 
6058 /*
6059  * fileio_decache () - Decache volume information. Used when the volume is
6060  * dismounted
6061  * return: void
6062  * vdes(in): I/O Volume descriptor
6063  */
6064 static void
6065 fileio_decache (THREAD_ENTRY * thread_p, int vol_fd)
6066 {
6067  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p, *prev_sys_vol_info_p;
6068  FILEIO_VOLUME_INFO *vol_info_p;
6069  int vol_id, prev_vol;
6070  int rv;
6071  APPLY_ARG arg = { 0 };
6072 
6073  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
6074  /* sys volume ? */
6075  for ((sys_vol_info_p = &fileio_Sys_vol_info_header.anchor, prev_sys_vol_info_p = NULL);
6076  (sys_vol_info_p != NULL && sys_vol_info_p->vdes != NULL_VOLDES);
6077  prev_sys_vol_info_p = sys_vol_info_p, sys_vol_info_p = sys_vol_info_p->next)
6078  {
6079  if (sys_vol_info_p->vdes == vol_fd)
6080  {
6081  if (prev_sys_vol_info_p == NULL)
6082  {
6083  if (fileio_Sys_vol_info_header.anchor.next != NULL)
6084  {
6085  /* copy next volinfo to anchor. */
6086  sys_vol_info_p = fileio_Sys_vol_info_header.anchor.next;
6087  fileio_Sys_vol_info_header.anchor.volid = sys_vol_info_p->volid;
6088  fileio_Sys_vol_info_header.anchor.vdes = sys_vol_info_p->vdes;
6089  fileio_Sys_vol_info_header.anchor.lockf_type = sys_vol_info_p->lockf_type;
6090  strncpy (fileio_Sys_vol_info_header.anchor.vlabel, sys_vol_info_p->vlabel, PATH_MAX);
6091  fileio_Sys_vol_info_header.anchor.next = sys_vol_info_p->next;
6092 #if defined(SERVER_MODE) && defined(WINDOWS)
6093  pthread_mutex_destroy (&sys_vol_info_p->sysvol_mutex);
6094 #endif /* WINDOWS */
6095  free_and_init (sys_vol_info_p);
6096  }
6097  else
6098  {
6099  fileio_Sys_vol_info_header.anchor.volid = NULL_VOLID;
6100  fileio_Sys_vol_info_header.anchor.vdes = NULL_VOLDES;
6101  fileio_Sys_vol_info_header.anchor.lockf_type = FILEIO_NOT_LOCKF;
6102  fileio_Sys_vol_info_header.anchor.vlabel[0] = '\0';
6103  fileio_Sys_vol_info_header.anchor.next = NULL;
6104 #if defined(SERVER_MODE) && defined(WINDOWS)
6105  pthread_mutex_destroy (&fileio_Sys_vol_info_header.anchor.sysvol_mutex);
6106 #endif /* WINDOWS */
6107  }
6108  }
6109  else
6110  {
6111  prev_sys_vol_info_p->next = sys_vol_info_p->next;
6112 #if defined(SERVER_MODE) && defined(WINDOWS)
6113  pthread_mutex_destroy (&sys_vol_info_p->sysvol_mutex);
6114 #endif /* WINDOWS */
6115  free_and_init (sys_vol_info_p);
6116  }
6117  fileio_Sys_vol_info_header.num_vols--;
6118  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6119  return;
6120  }
6121  }
6122  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6123  arg.vdes = vol_fd;
6125  if (vol_info_p)
6126  {
6127  vol_id = vol_info_p->volid;
6128 
6129  /* update next_perm_volid, if needed */
6130  rv = pthread_mutex_lock (&fileio_Vol_info_header.mutex);
6131  if (fileio_Vol_info_header.next_perm_volid == vol_id + 1)
6132  {
6133  fileio_Vol_info_header.next_perm_volid = fileio_find_previous_perm_volume (thread_p, vol_id) + 1;
6134  }
6135  pthread_mutex_unlock (&fileio_Vol_info_header.mutex);
6136 
6137  vol_info_p->volid = NULL_VOLID;
6138  vol_info_p->vdes = NULL_VOLDES;
6139  vol_info_p->lockf_type = FILEIO_NOT_LOCKF;
6140  vol_info_p->vlabel[0] = '\0';
6141 #if defined(SERVER_MODE) && defined(WINDOWS)
6142  pthread_mutex_destroy (&vol_info_p->vol_mutex);
6143 #endif /* WINDOWS */
6144  return;
6145  }
6146 
6147  arg.vdes = vol_fd;
6149  if (vol_info_p)
6150  {
6151  vol_id = vol_info_p->volid;
6152 
6153  /* update next_temp_volid, if needed */
6154  rv = pthread_mutex_lock (&fileio_Vol_info_header.mutex);
6155  if (fileio_Vol_info_header.next_temp_volid == vol_id - 1)
6156  {
6157  prev_vol = fileio_find_previous_temp_volume (thread_p, vol_id);
6158  /* if prev_vol is NULL_VOLID, this volume is last volume */
6159  fileio_Vol_info_header.next_temp_volid = (prev_vol != NULL_VOLID) ? (prev_vol - 1) : (LOG_MAX_DBVOLID);
6160  }
6161 
6162  pthread_mutex_unlock (&fileio_Vol_info_header.mutex);
6163 
6164  vol_info_p->volid = NULL_VOLID;
6165  vol_info_p->vdes = NULL_VOLDES;
6166  vol_info_p->lockf_type = FILEIO_NOT_LOCKF;
6167  vol_info_p->vlabel[0] = '\0';
6168 #if defined(SERVER_MODE) && defined(WINDOWS)
6169  pthread_mutex_destroy (&vol_info_p->vol_mutex);
6170 #endif /* WINDOWS */
6171  return;
6172  }
6173 }
6174 
6175 /*
6176  * fileio_get_volume_label ()
6177  * - Find the name of a mounted volume given its permanent volume identifier
6178  * return: Volume label
6179  * volid(in): Permanent volume identifier
6180  */
6181 char *
6182 fileio_get_volume_label (VOLID vol_id, bool is_peek)
6183 {
6184  FILEIO_VOLUME_INFO *vol_info_p;
6185  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
6186  char *vol_label_p = NULL;
6187  int i, j, rv;
6188  APPLY_ARG arg = { 0 };
6189 
6191  if (vol_id > NULL_VOLID)
6192  {
6193  /* perm volume */
6194  if (vol_id < fileio_Vol_info_header.next_temp_volid)
6195  {
6196  if (vol_id >= fileio_Vol_info_header.max_perm_vols)
6197  {
6198  return NULL;
6199  }
6200 
6201  i = vol_id / FILEIO_VOLINFO_INCREMENT;
6202  j = vol_id % FILEIO_VOLINFO_INCREMENT;
6203  }
6204  else
6205  {
6206  /* volid is the next temp volume id */
6207  if ((LOG_MAX_DBVOLID - vol_id) >= fileio_Vol_info_header.max_temp_vols)
6208  {
6209  return NULL;
6210  }
6211 
6212  i = fileio_Vol_info_header.num_volinfo_array - 1 - (LOG_MAX_DBVOLID - vol_id) / FILEIO_VOLINFO_INCREMENT;
6214  }
6215  vol_info_p = &fileio_Vol_info_header.volinfo[i][j];
6216  vol_label_p = (char *) vol_info_p->vlabel;
6217  }
6218  else
6219  {
6220  /* system volume */
6221  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
6222  arg.vol_id = vol_id;
6224  if (sys_vol_info_p)
6225  {
6226  vol_label_p = (char *) sys_vol_info_p->vlabel;
6227  }
6228 
6229  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6230  }
6231 
6232  if (!is_peek)
6233  {
6234  char *ret = strdup (vol_label_p);
6235 
6236  if (ret == NULL)
6237  {
6238  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) strlen (vol_label_p));
6239  }
6240 
6241  return ret;
6242  }
6243 
6244  return vol_label_p;
6245 }
6246 
6247 /*
6248  * fileio_get_volume_label_by_fd ()
6249  * - Find the name of a mounted volume given its file descriptor
6250  * return: Volume label
6251  * vol_fd(in): volume descriptor
6252  */
6253 char *
6254 fileio_get_volume_label_by_fd (int vol_fd, bool is_peek)
6255 {
6256  return fileio_get_volume_label (fileio_get_volume_id (vol_fd), is_peek);
6257 }
6258 
6259 
6260 /*
6261  * fileio_get_volume_id () - Find volume identifier of a mounted volume given its
6262  * descriptor
6263  * return: The volume identifier
6264  * vdes(in): I/O volume descriptor
6265  */
6266 static VOLID
6268 {
6269  FILEIO_VOLUME_INFO *vol_info_p;
6270  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
6271  VOLID vol_id = NULL_VOLID;
6272  int rv;
6273  APPLY_ARG arg = { 0 };
6274 
6276  /* sys volume ? */
6277  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
6278  arg.vdes = vol_fd;
6280  if (sys_vol_info_p)
6281  {
6282  vol_id = sys_vol_info_p->volid;
6283  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6284  return vol_id;
6285  }
6286 
6287  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6288 
6289  arg.vdes = vol_fd;
6291  if (vol_info_p)
6292  {
6293  return vol_info_p->volid;
6294  }
6295 
6296  arg.vdes = vol_fd;
6298  if (vol_info_p)
6299  {
6300  return vol_info_p->volid;
6301  }
6302 
6303  return vol_id;
6304 }
6305 
6306 static bool
6308 {
6309  return (util_compare_filepath (vol_info_p->vlabel, arg->vol_label) == 0);
6310 }
6311 
6312 /*
6313  * fileio_find_volume_id_with_label () - Find the volume identifier given the volume label of
6314  * a mounted volume
6315  * return: The volume identifier
6316  * vlabel(in): Volume Name/label
6317  */
6318 VOLID
6319 fileio_find_volume_id_with_label (THREAD_ENTRY * thread_p, const char *vol_label_p)
6320 {
6321  FILEIO_VOLUME_INFO *vol_info_p;
6322  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
6323  VOLID vol_id = NULL_VOLID;
6324  int rv;
6325  APPLY_ARG arg = { 0 };
6326 
6328  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
6329  arg.vol_label = vol_label_p;
6330  sys_vol_info_p = fileio_find_system_volume (thread_p, fileio_is_system_volume_label_equal, &arg);
6331  if (sys_vol_info_p)
6332  {
6333  vol_id = sys_vol_info_p->volid;
6334  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6335  return vol_id;
6336  }
6337 
6338  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6339 
6340  arg.vol_label = vol_label_p;
6341  vol_info_p = fileio_traverse_permanent_volume (thread_p, fileio_is_volume_label_equal, &arg);
6342  if (vol_info_p)
6343  {
6344  return vol_info_p->volid;
6345  }
6346 
6347  arg.vol_label = vol_label_p;
6348  vol_info_p = fileio_traverse_temporary_volume (thread_p, fileio_is_volume_label_equal, &arg);
6349  if (vol_info_p)
6350  {
6351  return vol_info_p->volid;
6352  }
6353 
6354  return vol_id;
6355 }
6356 
6357 bool
6359 {
6360  FILEIO_VOLUME_INFO *vol_info_p;
6361  APPLY_ARG arg = { 0 };
6362 
6363  if (volid == NULL_VOLID)
6364  {
6365  return false;
6366  }
6367 
6369 
6370  arg.vol_id = volid;
6371  vol_info_p = fileio_traverse_temporary_volume (thread_p, fileio_is_volume_id_equal, &arg);
6372  if (vol_info_p)
6373  {
6375  return true;
6376  }
6377 
6378  return false;
6379 }
6380 
6381 /*
6382  * fileio_is_permanent_volume_descriptor () - Check whether is permanent volume descriptor.
6383  * return: I/O volume descriptor
6384  * vol_fd(in): Volume descriptor to check.
6385  */
6386 bool
6388 {
6389  FILEIO_VOLUME_INFO *vol_info_p;
6390  APPLY_ARG arg = { 0 };
6391 
6392  if (vol_fd == NULL_VOLDES)
6393  {
6394  return false;
6395  }
6396 
6398 
6399  arg.vdes = vol_fd;
6401  if (vol_info_p)
6402  {
6403  return true;
6404  }
6405 
6406  return false;
6407 }
6408 
6409 VOLID
6411 {
6412  FILEIO_VOLUME_INFO *vol_info_p;
6413  APPLY_ARG arg = { 0 };
6414 
6415  if (volid == NULL_VOLID)
6416  {
6417  return NULL_VOLID;
6418  }
6419 
6421 
6422  arg.vol_id = volid;
6423  vol_info_p = fileio_traverse_permanent_volume (thread_p, fileio_is_volume_id_gt, &arg);
6424  if (vol_info_p)
6425  {
6427  return vol_info_p->volid;
6428  }
6429 
6430  return NULL_VOLID;
6431 }
6432 
6433 VOLID
6435 {
6436  FILEIO_VOLUME_INFO *vol_info_p;
6437  APPLY_ARG arg = { 0 };
6438 
6439  if (volid == NULL_VOLID)
6440  {
6441  return NULL_VOLID;
6442  }
6443 
6445 
6446  arg.vol_id = volid;
6448  if (vol_info_p)
6449  {
6451  return vol_info_p->volid;
6452  }
6453 
6454  return NULL_VOLID;
6455 }
6456 
6457 VOLID
6459 {
6460  FILEIO_VOLUME_INFO *vol_info_p;
6461  APPLY_ARG arg = { 0 };
6462 
6463  if (volid == NULL_VOLID)
6464  {
6465  return NULL_VOLID;
6466  }
6467 
6469 
6470  arg.vol_id = volid;
6472  if (vol_info_p)
6473  {
6475  return vol_info_p->volid;
6476  }
6477 
6478  return NULL_VOLID;
6479 }
6480 
6481 /*
6482  * fileio_get_volume_descriptor () - Find the volume descriptor given the volume permanent
6483  * identifier
6484  * return: I/O volume descriptor
6485  * volid(in): Permanent volume identifier
6486  */
6487 int
6489 {
6490  FILEIO_VOLUME_INFO *vol_info_p;
6491  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
6492  int vol_fd = NULL_VOLDES;
6493  int i, j, rv;
6494  APPLY_ARG arg = { 0 };
6495 
6497  if (vol_id > NULL_VOLID)
6498  {
6499  /* perm volume */
6500  if (vol_id < fileio_Vol_info_header.next_temp_volid)
6501  {
6502  if (vol_id >= fileio_Vol_info_header.max_perm_vols)
6503  {
6504  return NULL_VOLDES;
6505  }
6506  i = vol_id / FILEIO_VOLINFO_INCREMENT;
6507  j = vol_id % FILEIO_VOLINFO_INCREMENT;
6508  }
6509  else
6510  {
6511  /* volid is the next temp volume id */
6512  if ((LOG_MAX_DBVOLID - vol_id) >= fileio_Vol_info_header.max_temp_vols)
6513  {
6514  return NULL_VOLDES;
6515  }
6516  i = fileio_Vol_info_header.num_volinfo_array - 1 - (LOG_MAX_DBVOLID - vol_id) / FILEIO_VOLINFO_INCREMENT;
6518  }
6519  vol_info_p = &fileio_Vol_info_header.volinfo[i][j];
6520  vol_fd = vol_info_p->vdes;
6521  }
6522  else
6523  {
6524  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
6525  arg.vol_id = vol_id;
6527  if (sys_vol_info_p)
6528  {
6529  vol_fd = sys_vol_info_p->vdes;
6530  }
6531 
6532  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6533  }
6534 
6535  return vol_fd;
6536 }
6537 
6538 /*
6539  * fileio_find_volume_descriptor_with_label () - Find the volume descriptor given the volume label/name
6540  * return: Volume Name/label
6541  * vlabel(in): I/O volume descriptor
6542  */
6543 int
6545 {
6546  FILEIO_VOLUME_INFO *vol_info_p;
6547  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
6548  int vol_fd = NULL_VOLDES;
6549  int rv;
6550  APPLY_ARG arg = { 0 };
6551 
6553  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
6554  arg.vol_label = vol_label_p;
6556  if (sys_vol_info_p)
6557  {
6558  vol_fd = sys_vol_info_p->vdes;
6559  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6560  return vol_fd;
6561  }
6562 
6563  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6564 
6565  arg.vol_label = vol_label_p;
6567  if (vol_info_p)
6568  {
6569  return vol_info_p->vdes;
6570  }
6571 
6572  arg.vol_label = vol_label_p;
6574  if (vol_info_p)
6575  {
6576  return vol_info_p->vdes;
6577  }
6578 
6579  return vol_fd;
6580 }
6581 
6582 /*
6583  * fileio_get_lockf_type () - Find the lock type applied to a mounted volume
6584  * return: lockf_type
6585  * vdes(in): I/O volume descriptor
6586  */
6587 static FILEIO_LOCKF_TYPE
6589 {
6590  FILEIO_VOLUME_INFO *vol_info_p;
6591  FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p;
6592  FILEIO_LOCKF_TYPE lockf_type = FILEIO_NOT_LOCKF;
6593  int rv;
6594  APPLY_ARG arg = { 0 };
6595 
6597  rv = pthread_mutex_lock (&fileio_Sys_vol_info_header.mutex);
6598  arg.vdes = vol_fd;
6600  if (sys_vol_info_p)
6601  {
6602  lockf_type = sys_vol_info_p->lockf_type;
6603  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6604  return lockf_type;
6605  }
6606  pthread_mutex_unlock (&fileio_Sys_vol_info_header.mutex);
6607 
6608  arg.vdes = vol_fd;
6610  if (vol_info_p)
6611  {
6612  return vol_info_p->lockf_type;
6613  }
6614 
6615  arg.vdes = vol_fd;
6617  if (vol_info_p)
6618  {
6619  return vol_info_p->lockf_type;
6620  }
6621 
6622  return lockf_type;
6623 }
6624 
6625 #if 0
6626  /* currently, disable the following code. DO NOT DELETE ME NEED FUTURE OPTIMIZATION */
6627 static void
6628 fileio_determine_backup_buffer_size (FILEIO_BACKUP_SESSION * session_p, int buf_size)
6629 {
6630  int vol_size, max_buf_size;
6631  vol_size = DB_INT32_MAX; /* 2G */
6633  {
6634  vol_size = MIN (vol_size, (int) prm_get_bigint_value (PRM_ID_IO_BACKUP_MAX_VOLUME_SIZE));
6635  }
6636 
6638  max_buf_size = buf_size * prm_get_integer_value (PRM_ID_IO_BACKUP_NBUFFERS);
6639  while (max_buf_size > buf_size)
6640  {
6641  if (vol_size % max_buf_size < buf_size)
6642  {
6643  break; /* OK */
6644  }
6645  max_buf_size -= buf_size;
6646  }
6647 
6648  session_p->bkup.iosize = max_buf_size;
6649 }
6650 #endif
6651 
6652 static int
6654 {
6655  FILEIO_THREAD_INFO *thread_info_p;
6656  FILEIO_QUEUE *queue_p;
6657 #if defined(SERVER_MODE)
6658  int num_cpus;
6659  int rv;
6660 #endif /* SERVER_MODE */
6661 
6662  thread_info_p = &session_p->read_thread_info;
6663  queue_p = &thread_info_p->io_queue;
6664 
6665 #if defined(SERVER_MODE)
6666  rv = pthread_mutex_init (&thread_info_p->mtx, NULL);
6667  if (rv != 0)
6668  {
6671  }
6672 
6673  rv = pthread_cond_init (&thread_info_p->rcv, NULL);
6674  if (rv != 0)
6675  {
6677  return ER_CSS_PTHREAD_COND_INIT;
6678  }
6679 
6680  rv = pthread_cond_init (&thread_info_p->wcv, NULL);
6681  if (rv != 0)
6682  {
6684  return ER_CSS_PTHREAD_COND_INIT;
6685  }
6686 
6687  /* get the number of CPUs */
6688  num_cpus = fileio_os_sysconf ();
6689  /* check for the upper bound of threads */
6690  if (num_threads == FILEIO_BACKUP_NUM_THREADS_AUTO)
6691  {
6692  thread_info_p->num_threads = num_cpus;
6693  }
6694  else
6695  {
6696  thread_info_p->num_threads = MIN (num_threads, num_cpus * 2);
6697  }
6698  thread_info_p->num_threads = MIN (thread_info_p->num_threads, NUM_NORMAL_TRANS);
6699 #else /* SERVER_MODE */
6700  thread_info_p->num_threads = 1;
6701 #endif /* SERVER_MODE */
6702 #if defined(CUBRID_DEBUG)
6703  fprintf (stdout, "PRM_CSS_MAX_CLIENTS = %d, tp->num_threads = %d\n", prm_get_integer_value (PRM_ID_CSS_MAX_CLIENTS),
6704  thread_info_p->num_threads);
6705 #endif /* CUBRID_DEBUG */
6706  queue_p->size = 0;
6707  queue_p->head = NULL;
6708  queue_p->tail = NULL;
6709  queue_p->free_list = NULL;
6710 
6711  thread_info_p->initialized = true;
6712 
6713  return NO_ERROR;
6714 }
6715 
6716 /*
6717  * fileio_initialize_backup () - Initialize the backup session structure with the given
6718  * information
6719  * return: session or NULL
6720  * db_fullname(in): Name of the database to backup
6721  * backup_destination(in): Name of backup device (file or directory)
6722  * session(out): The session array
6723  * level(in): The presumed backup level
6724  * verbose_file_path(in): verbose mode file path
6725  * num_threads(in): number of threads
6726  * sleep_msecs(in): sleep interval in msecs
6727  */
6729 fileio_initialize_backup (const char *db_full_name_p, const char *backup_destination_p,
6730  FILEIO_BACKUP_SESSION * session_p, FILEIO_BACKUP_LEVEL level, const char *verbose_file_path,
6731  int num_threads, int sleep_msecs)
6732 {
6733  int vol_fd;
6734  int size;
6735  const char *db_nopath_name_p;
6736  struct stat stbuf;
6737  int buf_size;
6738  int io_page_size;
6739  const char *verbose_fp_mode;
6740 
6741  /*
6742  * First assume that backup device is a regular file or a raw device.
6743  * Adjustments are made at a later point, if the backup_destination is
6744  * a directory.
6745  */
6746  strncpy_bufsize (session_p->bkup.name, backup_destination_p);
6747  strncpy_bufsize (session_p->bkup.current_path, backup_destination_p);
6748  session_p->bkup.vlabel = session_p->bkup.name;
6749  session_p->bkup.vdes = NULL_VOLDES;
6750  session_p->bkup.dtype = FILEIO_BACKUP_VOL_UNKNOWN;
6751  session_p->dbfile.level = level;
6752  session_p->bkup.buffer = NULL;
6753  session_p->bkup.bkuphdr = NULL;
6754  session_p->dbfile.area = NULL;
6755 
6756  /* Now find out the type of backup_destination and the best page I/O for the backup. The accepted types are either
6757  * file, directory, or raw device. */
6758  while (stat (backup_destination_p, &stbuf) == -1)
6759  {
6760  /*
6761  * Could not stat or backup_destination is a file or directory that does not exist.
6762  * If the backup_destination does not exist, try to create it to make sure that we can write at this backup
6763  * destination.
6764  */
6765  vol_fd = fileio_open (backup_destination_p, FILEIO_DISK_FORMAT_MODE, FILEIO_DISK_PROTECTION_MODE);
6766  if (vol_fd == NULL_VOLDES)
6767  {
6769  return NULL;
6770  }
6771  fileio_close (vol_fd);
6772  continue;
6773  }
6774 
6775  if (S_ISDIR (stbuf.st_mode))
6776  {
6777  /*
6778  * This is a DIRECTORY where the backup is going to be sent.
6779  * The name of the backup file in this directory is labeled as databasename.bkLvNNN (Unix).
6780  * In this case, we may destroy any previous backup in this directory.
6781  */
6782  session_p->bkup.dtype = FILEIO_BACKUP_VOL_DIRECTORY;
6783  db_nopath_name_p = fileio_get_base_file_name (db_full_name_p);
6784  fileio_make_backup_name (session_p->bkup.name, db_nopath_name_p, backup_destination_p, level,
6786  }
6787  else if (S_ISREG (stbuf.st_mode))
6788  {
6789  /* Regular file. Remember the directory of this file, in case more volumes are needed. */
6790  session_p->bkup.dtype = FILEIO_BACKUP_VOL_DIRECTORY;
6791  fileio_get_directory_path (session_p->bkup.current_path, backup_destination_p);
6792  }
6793  else
6794  {
6795  /*
6796  * ASSUME that everything else is a special file such as a FIFO file, a device(character or block special file)
6797  * which is not named for I/O purposes. That is, the name of the device or regular file is used as the backup.
6798  */
6799  session_p->bkup.dtype = FILEIO_BACKUP_VOL_DEVICE;
6800  }
6801 
6802 #if defined(WINDOWS)
6803  buf_size = 4096;
6804 #else /* WINDOWS */
6805  buf_size = stbuf.st_blksize;
6806 #endif /* WINDOWS */
6807  /* User may override the default size by specifying a multiple of the natural block size for the device. */
6808  session_p->bkup.iosize = buf_size * prm_get_integer_value (PRM_ID_IO_BACKUP_NBUFFERS);
6809 #if 0
6810  /* currently, disable the following code. DO NOT DELETE ME NEED FUTURE OPTIMIZATION */
6811  fileio_determine_backup_buffer_size (session_p, buf_size);
6812 #endif
6814  && ((UINT64) session_p->bkup.iosize >=
6816  {
6818  "Backup block buffer size %ld must be less "
6819  "than backup volume size %ld, resetting buffer size to %d\n", session_p->bkup.iosize,
6821  session_p->bkup.iosize = MIN (buf_size, DB_INT32_MAX);
6822  }
6823 
6824 #if defined(CUBRID_DEBUG)
6825  /* These print statements are candidates for part of a "verbose" option to backupdb. */
6826  fprintf (stdout, "NATURAL BUFFER SIZE %ld (%d IO buffer blocks)\n", session_p->bkup.iosize,
6827  session_p->bkup.iosize / buf_size);
6828  fprintf (stdout, "BACKUP_MAX_VOLUME_SIZE = %ld\n", prm_get_bigint_value (PRM_ID_IO_BACKUP_MAX_VOLUME_SIZE));
6829 #endif /* CUBRID_DEBUG */
6830  /*
6831  * Initialize backup device related information.
6832  *
6833  * Make sure it is large enough to hold various headers and pages.
6834  * Beware that upon restore, both the backup buffer size and the
6835  * database io pagesize may be different.
6836  */
6837  io_page_size = IO_PAGESIZE;
6838  if (session_p->dbfile.level == FILEIO_BACKUP_FULL_LEVEL)
6839  {
6840  io_page_size *= FILEIO_FULL_LEVEL_EXP;
6841  }
6842 
6844 
6845  session_p->bkup.buffer = (char *) malloc (session_p->bkup.iosize);
6846  if (session_p->bkup.buffer == NULL)
6847  {
6849 
6850  goto error;
6851  }
6852 
6853  session_p->dbfile.area = (FILEIO_BACKUP_PAGE *) malloc (size);
6854  if (session_p->dbfile.area == NULL)
6855  {
6857 
6858  goto error;
6859  }
6860 
6862  if (session_p->bkup.bkuphdr == NULL)
6863  {
6865 
6866  goto error;
6867  }
6868 
6869  session_p->bkup.ptr = session_p->bkup.buffer;
6870  session_p->bkup.count = 0;
6871  session_p->bkup.voltotalio = 0;
6872  session_p->bkup.alltotalio = 0;
6874  session_p->bkup.bkuphdr->level = level;
6875  session_p->bkup.bkuphdr->bkup_iosize = session_p->bkup.iosize;
6877  session_p->bkup.bkuphdr->start_time = 0;
6878  session_p->bkup.bkuphdr->end_time = -1;
6879  memset (session_p->bkup.bkuphdr->db_prec_bkvolname, 0, sizeof (session_p->bkup.bkuphdr->db_prec_bkvolname));
6880  memset (session_p->bkup.bkuphdr->db_next_bkvolname, 0, sizeof (session_p->bkup.bkuphdr->db_next_bkvolname));
6883  /* Initialize database file related information */
6884  LSA_SET_NULL (&session_p->dbfile.lsa);
6885  session_p->dbfile.vlabel = NULL;
6886  session_p->dbfile.volid = NULL_VOLID;
6887  session_p->dbfile.vdes = NULL_VOLDES;
6888  session_p->dbfile.nbytes = -1;
6889  FILEIO_SET_BACKUP_PAGE_ID (session_p->dbfile.area, NULL_PAGEID, io_page_size);
6890 
6891 #if defined(CUBRID_DEBUG)
6892  fprintf (stdout, "fileio_initialize_backup: %d\t%d,\t%d\n",
6893  ((FILEIO_BACKUP_PAGE *) (session_p->dbfile.area))->iopageid,
6894  *(PAGEID *) (((char *) (session_p->dbfile.area)) + offsetof (FILEIO_BACKUP_PAGE, iopage) + io_page_size),
6895  io_page_size);
6896 #endif
6897 
6898  if (fileio_initialize_backup_thread (session_p, num_threads) != NO_ERROR)
6899  {
6900  goto error;
6901  }
6902 
6903  if (verbose_file_path && *verbose_file_path)
6904  {
6905  if (session_p->type == FILEIO_BACKUP_WRITE && level == 0)
6906  {
6907  verbose_fp_mode = "w";
6908  }
6909  else
6910  {
6911  verbose_fp_mode = "a";
6912  }
6913 
6914  session_p->verbose_fp = fopen (verbose_file_path, verbose_fp_mode);
6915  if (session_p->verbose_fp == NULL)
6916  {
6918 
6919  goto error;
6920  }
6921 
6922  setbuf (session_p->verbose_fp, NULL);
6923  }
6924  else
6925  {
6926  session_p->verbose_fp = NULL;
6927  }
6928 
6929  session_p->sleep_msecs = sleep_msecs;
6930 
6931  return session_p;
6932 
6933 error:
6934  if (session_p->bkup.buffer != NULL)
6935  {
6936  free_and_init (session_p->bkup.buffer);
6937  }
6938  if (session_p->dbfile.area != NULL)
6939  {
6940  free_and_init (session_p->dbfile.area);
6941  }
6942  if (session_p->bkup.bkuphdr != NULL)
6943  {
6944  free_and_init (session_p->bkup.bkuphdr);
6945  }
6946  if (session_p->verbose_fp != NULL)
6947  {
6948  fclose (session_p->verbose_fp);
6949  session_p->verbose_fp = NULL;
6950  }
6951 
6952  return NULL;
6953 }
6954 
6955 /*
6956  * fileio_finalize_backup_thread() -
6957  * return: void
6958  *
6959  * session_p(in/out):
6960  * zip_method(in):
6961  */
6962 static void
6964 {
6965  FILEIO_THREAD_INFO *tp;
6966  FILEIO_QUEUE *qp;
6967  FILEIO_NODE *node, *node_next;
6968 #if defined(SERVER_MODE)
6969  int rv;
6970 #endif /* SERVER_MODE */
6971 
6972  tp = &session_p->read_thread_info;
6973  qp = &tp->io_queue;
6974 
6975  if (tp->initialized == false)
6976  {
6977  return;
6978  }
6979 
6980 #if defined(SERVER_MODE)
6981  rv = pthread_mutex_destroy (&tp->mtx);
6982  if (rv != 0)
6983  {
6985  }
6986 
6987  rv = pthread_cond_destroy (&tp->rcv);
6988  if (rv != 0)
6989  {
6991  }
6992 
6993  rv = pthread_cond_destroy (&tp->wcv);
6994  if (rv != 0)
6995  {
6997  }
6998 #endif /* SERVER_MODE */
6999 
7000  while (qp->size > 0)
7001  {
7002  node = fileio_delete_queue_head (qp);
7003  (void) fileio_free_node (qp, node);
7004  }
7005 
7006  for (node = qp->free_list; node; node = node_next)
7007  {
7008  node_next = node->next;
7009  switch (zip_method)
7010  {
7011  case FILEIO_ZIP_LZ4_METHOD:
7012  if (node->zip_info != NULL)
7013  {
7014  free_and_init (node->zip_info);
7015  }
7016  break;
7018  break;
7020  break;
7021  default:
7022  break;
7023  }
7024 
7025  if (node->area != NULL)
7026  {
7027  free_and_init (node->area);
7028  }
7029 
7030  if (node != NULL)
7031  {
7032  free_and_init (node);
7033  }
7034  }
7035 
7036  qp->free_list = NULL;
7037 
7038  tp->initialized = false;
7039 }
7040 
7041 /*
7042  * fileio_abort_backup () - The backup session is aborted
7043  * return: void
7044  * session(in/out): The session array
7045  * does_unformat_bk(in): set to TRUE to delete backup volumes we know about
7046  *
7047  * Note: The currently created backup file can be removed if desired. This
7048  * routine is called in for normal cleanup as well as to handle
7049  * exceptions.
7050  */
7051 void
7052 fileio_abort_backup (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p, bool does_unformat_bk)
7053 {
7054  FILEIO_BACKUP_HEADER *backup_header_p = session_p->bkup.bkuphdr;
7055  FILEIO_ZIP_METHOD zip_method;
7056 
7057  zip_method = backup_header_p ? backup_header_p->zip_method : FILEIO_ZIP_NONE_METHOD;
7058  /* Remove the currently created backup */
7059  if (session_p->bkup.vdes != NULL_VOLDES)
7060  {
7061  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DIRECTORY)
7062  {
7063  if (session_p->type == FILEIO_BACKUP_READ)
7064  {
7065  /* access backup device for read */
7066  fileio_dismount_without_fsync (thread_p, session_p->bkup.vdes);
7067  }
7068  else
7069  {
7070  /* access backup device for write */
7071  fileio_dismount (thread_p, session_p->bkup.vdes);
7072  }
7073  }
7074  else
7075  {
7076  fileio_dismount_without_fsync (thread_p, session_p->bkup.vdes);
7077  }
7078  }
7079 
7080  /* Destroy the current backup volumes */
7081  if (does_unformat_bk)
7082  {
7083  /* Remove current backup volume */
7084  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DIRECTORY
7086  {
7087  fileio_unformat (thread_p, session_p->bkup.vlabel);
7088  }
7089 
7090  /* Remove backup volumes previous to this one */
7091  if (session_p->bkup.bkuphdr)
7092  {
7093  fileio_remove_all_backup (thread_p, session_p->bkup.bkuphdr->level);
7094  }
7095  }
7096 
7097  if (session_p->verbose_fp)
7098  {
7099  fclose (session_p->verbose_fp);
7100  session_p->verbose_fp = NULL;
7101  }
7102 
7103  /* Deallocate memory space */
7104  if (session_p->bkup.buffer != NULL)
7105  {
7106  free_and_init (session_p->bkup.buffer);
7107  }
7108 
7109  if (session_p->dbfile.area != NULL)
7110  {
7111  free_and_init (session_p->dbfile.area);
7112  }
7113 
7114  if (session_p->bkup.bkuphdr != NULL)
7115  {
7116  free_and_init (session_p->bkup.bkuphdr);
7117  }
7118 
7120  LSA_SET_NULL (&session_p->dbfile.lsa);
7122  session_p->dbfile.vdes = NULL_VOLDES;
7123  session_p->dbfile.volid = NULL_VOLID;
7124  session_p->dbfile.vlabel = NULL;
7125  session_p->dbfile.nbytes = -1;
7126  session_p->dbfile.area = NULL;
7127  session_p->bkup.vdes = NULL_VOLDES;
7128  session_p->bkup.vlabel = NULL;
7129  session_p->bkup.iosize = -1;
7130  session_p->bkup.count = 0;
7131  session_p->bkup.voltotalio = 0;
7132  session_p->bkup.alltotalio = 0;
7133  session_p->bkup.buffer = session_p->bkup.ptr = NULL;
7134  session_p->bkup.bkuphdr = NULL;
7135  fileio_finalize_backup_thread (session_p, zip_method);
7136 }
7137 
7138 /*
7139  * fileio_start_backup () - Start a backup session
7140  * return: session or NULL
7141  * db_fullname(in): Name of the database to backup
7142  * db_creation(in): Creation time of database
7143  * backup_level(in): Backup level
7144  * backup_start_lsa(in): start lsa for backup
7145  * backup_chkpt_lsa(in): checkpoint lsa for backup
7146  * all_levels_info(in): previous backup info per level
7147  * session(in/out): The session array
7148  * zip_method(in): compression method
7149  * zip_level(in): compression evel
7150  *
7151  * Note: Note that fileio_initialize_backup must have already been invoked on the
7152  * session.
7153  */
7155 fileio_start_backup (THREAD_ENTRY * thread_p, const char *db_full_name_p, INT64 * db_creation_time_p,
7156  FILEIO_BACKUP_LEVEL backup_level, LOG_LSA * backup_start_lsa_p, LOG_LSA * backup_checkpoint_lsa_p,
7157  FILEIO_BACKUP_RECORD_INFO * all_levels_info_p, FILEIO_BACKUP_SESSION * session_p,
7158  FILEIO_ZIP_METHOD zip_method, FILEIO_ZIP_LEVEL zip_level)
7159 {
7160  FILEIO_BACKUP_HEADER *backup_header_p;
7161  int i;
7162 
7163  /* Complete the session array initialization and create/open the backup destination device. */
7164  LSA_COPY (&session_p->dbfile.lsa, backup_start_lsa_p);
7165  session_p->bkup.vdes =
7166  fileio_create_backup_volume (thread_p, db_full_name_p, session_p->bkup.vlabel, LOG_DBCOPY_VOLID, false, false,
7167  (session_p->dbfile.level == FILEIO_BACKUP_FULL_LEVEL)
7169  if (session_p->bkup.vdes == NULL_VOLDES)
7170  {
7171  goto error;
7172  }
7173 
7174  /* Remember name of new backup volume */
7175  if (fileio_add_volume_to_backup_info (session_p->bkup.name, session_p->dbfile.level,
7177  {
7178  goto error;
7179  }
7180 
7181  /* Write the description/header of the backup to the backup device */
7182 
7183  backup_header_p = session_p->bkup.bkuphdr;
7184  backup_header_p->iopageid = FILEIO_BACKUP_START_PAGE_ID;
7185  strncpy (backup_header_p->magic, CUBRID_MAGIC_DATABASE_BACKUP, CUBRID_MAGIC_MAX_LENGTH);
7186  strncpy_bufsize (backup_header_p->db_release, rel_release_string ());
7187  strncpy_bufsize (backup_header_p->db_fullname, db_full_name_p);
7188  backup_header_p->db_creation = *db_creation_time_p;
7189  backup_header_p->db_iopagesize = IO_PAGESIZE;
7190  backup_header_p->db_compatibility = rel_disk_compatible ();
7191  backup_header_p->level = backup_level;
7192  LSA_COPY (&backup_header_p->start_lsa, backup_start_lsa_p);
7193  LSA_COPY (&backup_header_p->chkpt_lsa, backup_checkpoint_lsa_p);
7194 
7196  {
7197  if (all_levels_info_p)
7198  {
7199  if (i == FILEIO_BACKUP_FULL_LEVEL)
7200  {
7201  LSA_SET_NULL (&backup_header_p->previnfo[i].lsa);
7202  }
7203  else
7204  {
7205  LSA_COPY (&backup_header_p->previnfo[i].lsa, &all_levels_info_p[i].lsa);
7206  }
7207  backup_header_p->previnfo[i].at_time = all_levels_info_p[i].at_time;
7208  }
7209  else
7210  {
7211  LSA_SET_NULL (&backup_header_p->previnfo[i].lsa);
7212  backup_header_p->previnfo[i].at_time = 0;
7213  }
7214  }
7215 
7216  backup_header_p->start_time = time (NULL);
7217  backup_header_p->unit_num = FILEIO_INITIAL_BACKUP_UNITS;
7218  backup_header_p->bkpagesize = backup_header_p->db_iopagesize;
7219 
7220  if (backup_level == FILEIO_BACKUP_FULL_LEVEL)
7221  {
7222  backup_header_p->bkpagesize *= FILEIO_FULL_LEVEL_EXP;
7223  }
7224 
7225  backup_header_p->zip_method = zip_method;
7226  backup_header_p->zip_level = zip_level;
7227 
7228  if (backup_header_p->zip_method == FILEIO_ZIP_LZ4_METHOD
7229  && FILEIO_DBVOLS_IO_PAGE_SIZE (backup_header_p) > LZ4_MAX_INPUT_SIZE)
7230  {
7231  goto error;
7232  }
7233 
7234  /* Now write this information to the backup volume. */
7235  if (fileio_write_backup_header (session_p) != NO_ERROR)
7236  {
7237  goto error;
7238  }
7239 
7240  return session_p;
7241 
7242 error:
7243  fileio_abort_backup (thread_p, session_p, true);
7244  return NULL;
7245 }
7246 
7247 /*
7248  * fileio_write_backup_end_time_to_header () - Write the end time of backup
7249  * to backup volume header
7250  * return: error status
7251  * session(in): backup session
7252  * end_time: the end time of backup
7253  */
7254 static int
7256 {
7257  const char *first_bkvol_name;
7258  int vdes, nbytes;
7259 
7260  first_bkvol_name =
7263 
7264  if (first_bkvol_name == NULL)
7265  {
7266  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_MOUNT_FAIL, 1, "(backup volume name is null)");
7267  return ER_IO_MOUNT_FAIL;
7268  }
7269 
7270  if (strncmp (first_bkvol_name, session_p->bkup.vlabel, PATH_MAX) == 0)
7271  {
7272  session_p->bkup.bkuphdr->end_time = end_time;
7273  lseek (session_p->bkup.vdes, 0, SEEK_SET);
7274  fileio_write_backup_header (session_p);
7275  }
7276  else
7277  {
7278  vdes = fileio_open (first_bkvol_name, O_RDWR, 0);
7279  if (vdes == NULL_VOLDES)
7280  {
7282  return ER_IO_MOUNT_FAIL;
7283  }
7284 
7285  lseek (vdes, offsetof (FILEIO_BACKUP_HEADER, end_time), SEEK_SET);
7286  nbytes = write (vdes, (char *) &end_time, sizeof (INT64));
7287  if (nbytes != sizeof (INT64))
7288  {
7289  er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_WRITE, 2, 1, first_bkvol_name);
7290  fileio_close (vdes);
7291  return ER_IO_WRITE;
7292  }
7293  fileio_close (vdes);
7294  }
7295 
7296  return NO_ERROR;
7297 }
7298 
7299 /*
7300  * fileio_write_backup_end_time_to_last_page () - Write the end time of backup
7301  * to the last page of backup
7302  * return: void
7303  * session(in): backup session
7304  * end_time: the end time of backup
7305  */
7306 static void
7308 {
7309  char *write_to;
7310 
7311  write_to = ((char *) &(session_p->dbfile.area->iopageid)) + offsetof (FILEIO_BACKUP_PAGE, iopage);
7312  memcpy (write_to, (char *) &end_time, sizeof (INT64));
7313 }
7314 
7315 /*
7316  * fileio_read_backup_end_time_from_last_page () - Read the end time of backup
7317  * from the last page of backup
7318  * return: void
7319  * session(in): backup session
7320  */
7321 static void
7323 {
7324  char *read_from;
7325 
7326  read_from = ((char *) &(session_p->dbfile.area->iopageid)) + offsetof (FILEIO_BACKUP_PAGE, iopage);
7327  memcpy ((char *) &(session_p->bkup.bkuphdr->end_time), read_from, sizeof (INT64));
7328 }
7329 
7330 /*
7331  * fileio_finish_backup () - Finish the backup session successfully
7332  * return: session or NULL
7333  * session(in/out): The session array
7334  */
7337 {
7338  int nbytes;
7339  char *msg_area = NULL;
7340  char io_time_val[CTIME_MAX];
7341  INT64 end_time;
7342 
7343  end_time = (INT64) time (NULL);
7344 
7345  /*
7346  * Indicate end of backup and flush any buffered data.
7347  * Note that only the end of backup marker is written,
7348  * so callers of io_restore_read must check for the appropriate
7349  * end of backup condition.
7350  */
7352  nbytes = offsetof (FILEIO_BACKUP_PAGE, iopage);
7353 
7354  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DEVICE)
7355  {
7356  fileio_write_backup_end_time_to_last_page (session_p, end_time);
7357  nbytes += sizeof (INT64);
7358  }
7359 
7360  if (fileio_write_backup (thread_p, session_p, nbytes) != NO_ERROR)
7361  {
7362  return NULL;
7363  }
7364 
7365  if (session_p->bkup.count > 0)
7366  {
7367 #if defined(CUBRID_DEBUG)
7368  fprintf (stdout, "io_backup_end: iosize = %ld, count = %ld, voltotalio = %ld : EOF JUNK\n",
7369  session_p->bkup.iosize, session_p->bkup.count, session_p->bkup.voltotalio);
7370 #endif /* CUBRID_DEBUG */
7371  /*
7372  * We must add some junk at the end of the buffered area since some
7373  * backup devices (e.g., Fixed-length I/O tape devices such as
7374  * 1/4" cartridge tape devices), requires number of bytes to write
7375  * to be a multiple of the physical record size (io_size).
7376  */
7377  nbytes = CAST_BUFLEN (session_p->bkup.iosize - session_p->bkup.count);
7378  memset (session_p->bkup.ptr, '\0', nbytes);
7379  session_p->bkup.count = session_p->bkup.iosize;
7380  /* Flush any buffered information */
7381  if (fileio_flush_backup (thread_p, session_p) != NO_ERROR)
7382  {
7383  return NULL;
7384  }
7385  }
7386 
7387  /*
7388  * Now, make sure that all the information is physically written to
7389  * the backup device. That is, make sure that nobody (e.g., backup
7390  * device controller or OS) is caching data.
7391  */
7392 
7393  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DIRECTORY)
7394  {
7395  if (fileio_write_backup_end_time_to_header (session_p, end_time) != NO_ERROR)
7396  {
7397  return NULL;
7398  }
7399 
7400  if (fileio_synchronize (thread_p, session_p->bkup.vdes, session_p->bkup.name,
7401  FILEIO_SYNC_ONLY) != session_p->bkup.vdes)
7402  {
7403  return NULL;
7404  }
7405  }
7406 
7407  /* Tell user that current backup volume just completed */
7408 #if defined(SERVER_MODE) && !defined(WINDOWS)
7410  session_p->bkup.bkuphdr->level, session_p->bkup.bkuphdr->unit_num,
7412  fileio_ctime (&session_p->bkup.bkuphdr->start_time, io_time_val)) < 0)
7413 #else /* SERVER_MODE && !WINDOWS */
7415  session_p->bkup.bkuphdr->level, session_p->bkup.bkuphdr->unit_num,
7417  fileio_ctime (&session_p->bkup.bkuphdr->start_time, io_time_val)) < 0)
7418 #endif /* SERVER_MODE && !WINDOWS */
7419  {
7420  /* Note: we do not know the exact malloc size that failed */
7422  return NULL;
7423  }
7424  else
7425  {
7426  (void) fileio_request_user_response (thread_p, FILEIO_PROMPT_DISPLAY_ONLY, msg_area, NULL, NULL, -1, -1, NULL,
7427  -1);
7428  /* Note: Not free_and_init */
7429  free (msg_area);
7430  }
7431 
7432  return session_p;
7433 }
7434 
7435 /*
7436  * fileio_remove_all_backup () - REMOVE ALL BACKUP VOLUMES
7437  * return: void
7438  * start_level(in): the starting level to remove
7439  *
7440  * Note: Initialize the backup session structure with the given information.
7441  * Remove backup. Cleanup backup. This routine deletes all backups of
7442  * a higher level as well. Furthermore, this routine assumes that the
7443  * bkvinf cache has already been read in from the bkvinf file.
7444  */
7445 void
7446 fileio_remove_all_backup (THREAD_ENTRY * thread_p, int start_level)
7447 {
7448  int level;
7449  int unit_num;
7450  const char *vol_name_p;
7451 
7452  level = start_level;
7453  if (level >= FILEIO_BACKUP_UNDEFINED_LEVEL)
7454  {
7455  return;
7456  }
7457 
7458  if (level < FILEIO_BACKUP_FULL_LEVEL)
7459  {
7460  level = FILEIO_BACKUP_FULL_LEVEL;
7461  }
7462 
7463  do
7464  {
7465  unit_num = FILEIO_INITIAL_BACKUP_UNITS;
7466  while (true)
7467  {
7468  vol_name_p =
7470  if (vol_name_p == NULL)
7471  {
7472  break;
7473  }
7474 
7475  if (fileio_is_volume_exist_and_file (vol_name_p))
7476  {
7477  fileio_unformat (thread_p, vol_name_p);
7478  }
7479  }
7480 
7481  level++;
7482  }
7483  while (level < FILEIO_BACKUP_UNDEFINED_LEVEL);
7484  /* Remove all names just deleted from memory */
7486 }
7487 
7488 /*
7489  * fileio_allocate_node () -
7490  * return:
7491  * qp(in):
7492  * backup_hdr(in):
7493  */
7494 static FILEIO_NODE *
7496 {
7497  FILEIO_NODE *node_p;
7498  int size;
7499  int zip_info_size, buf_size;
7500 
7501  if (queue_p->free_list) /* re-use already alloced nodes */
7502  {
7503  node_p = queue_p->free_list;
7504  queue_p->free_list = node_p->next; /* cut-off */
7505  return node_p;
7506  }
7507 
7508  /* at here, need to alloc */
7509  node_p = (FILEIO_NODE *) malloc (sizeof (FILEIO_NODE));
7510  if (node_p == NULL)
7511  {
7513  goto exit_on_error;
7514  }
7515 
7516  node_p->area = NULL;
7517  node_p->zip_info = NULL;
7518  size = FILEIO_DBVOLS_IO_PAGE_SIZE (backup_header_p);
7519  node_p->area = (FILEIO_BACKUP_PAGE *) malloc (size);
7520  if (node_p == NULL)
7521  {
7523  goto exit_on_error;
7524  }
7525 
7526  switch (backup_header_p->zip_method)
7527  {
7528  case FILEIO_ZIP_LZ4_METHOD:
7529  assert (size <= LZ4_MAX_INPUT_SIZE);
7530  buf_size = LZ4_compressBound (size);
7531  zip_info_size = offsetof (FILEIO_ZIP_INFO, zip_page) + sizeof (int) + buf_size;
7532  node_p->zip_info = (FILEIO_ZIP_INFO *) malloc (zip_info_size);
7533  if (node_p->zip_info == NULL)
7534  {
7536  goto exit_on_error;
7537  }
7538  node_p->zip_info->buf_size = buf_size;
7539 
7540  break;
7542  break;
7544  break;
7545  default:
7546  break;
7547  }
7548 
7549 exit_on_end:
7550 
7551  return node_p;
7552 exit_on_error:
7553 
7554  if (node_p)
7555  {
7556  if (node_p->zip_info)
7557  {
7558  free_and_init (node_p->zip_info);
7559  }
7560 
7561  if (node_p->area)
7562  {
7563  free_and_init (node_p->area);
7564  }
7565 
7566  free_and_init (node_p);
7567  }
7568 
7569  node_p = NULL;
7570  goto exit_on_end;
7571 }
7572 
7573 /*
7574  * fileio_free_node () -
7575  * return:
7576  * qp(in):
7577  * node(in):
7578  */
7579 static FILEIO_NODE *
7581 {
7582  if (node_p)
7583  {
7584  node_p->prev = node_p->next = NULL;
7585  node_p->next = queue_p->free_list; /* add to free list */
7586  queue_p->free_list = node_p;
7587  }
7588 
7589  return node_p;
7590 }
7591 
7592 /*
7593  * fileio_append_queue () -
7594  * return:
7595  * qp(in):
7596  * node(in):
7597  */
7598 #if defined(SERVER_MODE)
7599 static FILEIO_NODE *
7600 fileio_append_queue (FILEIO_QUEUE * queue_p, FILEIO_NODE * node_p)
7601 {
7602  if (node_p)
7603  {
7604  node_p->prev = node_p->next = NULL;
7605  node_p->next = queue_p->tail; /* add to tail */
7606  if (queue_p->tail)
7607  {
7608  queue_p->tail->prev = node_p;
7609  }
7610  queue_p->tail = node_p;
7611  if (queue_p->head == NULL)
7612  {
7613  /* the first */
7614  queue_p->head = node_p;
7615  }
7616 
7617  queue_p->size++;
7618  }
7619 
7620  return node_p;
7621 }
7622 #endif /* SERVER_MODE */
7623 
7624 /*
7625  * fileio_delete_queue_head () -
7626  * return:
7627  * qp(in):
7628  */
7629 static FILEIO_NODE *
7631 {
7632  FILEIO_NODE *node;
7633 
7634  node = queue_p->head;
7635  if (node)
7636  {
7637  if (node == queue_p->tail) /* only one node */
7638  {
7639  queue_p->tail = NULL;
7640  }
7641  else
7642  {
7643  node->prev->next = NULL; /* cut-off */
7644  }
7645 
7646  queue_p->head = node->prev;
7647  queue_p->size--;
7648  }
7649 
7650  return node;
7651 }
7652 
7653 /*
7654  * fileio_compress_backup_node () -
7655  * return:
7656  * node(in):
7657  * backup_hdr(in):
7658  */
7659 static int
7661 {
7662  int error = NO_ERROR, local_buf_len;
7663  FILEIO_ZIP_PAGE *zip_page;
7664 
7665  if (!node_p || !node_p->zip_info || !backup_header_p)
7666  {
7667  goto exit_on_error;
7668  }
7669 
7670  assert (node_p->nread >= 0);
7671 
7672  zip_page = &node_p->zip_info->zip_page;
7673 
7674  switch (backup_header_p->zip_method)
7675  {
7676  case FILEIO_ZIP_LZ4_METHOD:
7677  /* The alternative is compress faster - best speed, but, require more memory alloc */
7678  local_buf_len =
7679  LZ4_compress_default ((char *) node_p->area, zip_page->buf, (int) node_p->nread, node_p->zip_info->buf_size);
7680  if (local_buf_len <= 0)
7681  {
7682  /* best reduction */
7683  error = ER_IO_LZ4_COMPRESS_FAIL;
7684  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 4, backup_header_p->zip_method,
7685  fileio_get_zip_method_string (backup_header_p->zip_method), backup_header_p->zip_level,
7686  fileio_get_zip_level_string (backup_header_p->zip_level));
7687 #if defined(CUBRID_DEBUG)
7688  fprintf (stdout,
7689  "internal error - compression failed: node->pageid = %d, node->nread = %d, "
7690  "buf_len = %d, buf_size = %d\n",
7691  node_p->pageid, node_p->nread, local_buf_len, node_p->zip_info->buf_size);
7692 #endif /* CUBRID_DEBUG */
7693  goto exit_on_error;
7694  }
7695 
7696  assert (local_buf_len < node_p->zip_info->buf_size);
7697 
7698  if ((ssize_t) local_buf_len < node_p->nread)
7699  {
7700  /* already write compressed block */
7701  zip_page->buf_len = local_buf_len;
7702  }
7703  else
7704  {
7705  /* not compressible - write uncompressed block */
7706  zip_page->buf_len = (int) node_p->nread;
7707  memcpy (zip_page->buf, node_p->area, node_p->nread);
7708  }
7709  break;
7711  error = ER_LOG_DBBACKUP_FAIL;
7712  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 4, backup_header_p->zip_method,
7713  fileio_get_zip_method_string (backup_header_p->zip_method), backup_header_p->zip_level,
7714  fileio_get_zip_level_string (backup_header_p->zip_level));
7715  goto exit_on_error;
7717  break;
7718  default:
7719  break;
7720  }
7721 
7722 exit_on_end:
7723 
7724  return error;
7725 exit_on_error:
7726 
7727  if (error == NO_ERROR)
7728  {
7729  error = ER_FAILED;
7730  }
7731  goto exit_on_end;
7732 }
7733 
7734 /*
7735  * fileio_write_backup_node () -
7736  * return:
7737  * thread_p(in):
7738  * session_p(in/out):
7739  * node_p(in):
7740  * backup_header_p(in):
7741  */
7742 static int
7744  FILEIO_BACKUP_HEADER * backup_header_p)
7745 {
7746  int error = NO_ERROR;
7747 
7748  if (!session_p || !node_p || !backup_header_p)
7749  {
7750  goto exit_on_error;
7751  }
7752 
7753  switch (backup_header_p->zip_method)
7754  {
7755  case FILEIO_ZIP_LZ4_METHOD:
7756  /* Skip allocated block size inside of FILEIO_ZIP_PAGE */
7757 
7758  session_p->dbfile.area = (FILEIO_BACKUP_PAGE *) & node_p->zip_info->zip_page;
7759  node_p->nread = sizeof (int) + node_p->zip_info->zip_page.buf_len;
7760  break;
7762  error = ER_LOG_DBBACKUP_FAIL;
7763  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 4, backup_header_p->zip_method,
7764  fileio_get_zip_method_string (backup_header_p->zip_method), backup_header_p->zip_level,
7765  fileio_get_zip_level_string (backup_header_p->zip_level));
7766  goto exit_on_error;
7768  break;
7769  default:
7770  session_p->dbfile.area = node_p->area;
7771  break;
7772  }
7773 
7774  if (fileio_write_backup (thread_p, session_p, node_p->nread) != NO_ERROR)
7775  {
7776  goto exit_on_error;
7777  }
7778 
7779 exit_on_end:
7780 
7781  return error;
7782 
7783 exit_on_error:
7784 
7785  if (error == NO_ERROR)
7786  {
7787  error = ER_FAILED;
7788  }
7789  goto exit_on_end;
7790 }
7791 
7792 /*
7793  * fileio_read_backup_volume () -
7794  * return:
7795  * session(in/out):
7796  */
7797 #if defined(SERVER_MODE)
7798 static void
7799 fileio_read_backup_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p)
7800 {
7801  FILEIO_THREAD_INFO *thread_info_p;
7802  FILEIO_QUEUE *queue_p;
7803  FILEIO_NODE *node_p = NULL;
7804  int rv;
7805  bool need_unlock = false;
7806  FILEIO_BACKUP_HEADER *backup_header_p;
7807  FILEIO_BACKUP_PAGE *save_area_p;
7808 
7809  if (thread_p == NULL)
7810  {
7811  thread_p = thread_get_thread_entry_info ();
7812  if (thread_p == NULL)
7813  {
7815  return;
7816  }
7817  }
7818 
7819  if (!session_p)
7820  {
7821  return;
7822  }
7823 
7824  thread_info_p = &session_p->read_thread_info;
7825  queue_p = &thread_info_p->io_queue;
7826  /* thread service routine has tran_index_lock, and should release before it is working */
7827  pthread_mutex_unlock (&thread_p->tran_index_lock);
7828  thread_p->tran_index = thread_info_p->tran_index;
7829 #if defined(CUBRID_DEBUG)
7830  fprintf (stdout, "start io_backup_volume_read, session = %p\n", session_p);
7831 #endif /* CUBRID_DEBUG */
7832  backup_header_p = session_p->bkup.bkuphdr;
7833  node_p = NULL; /* init */
7834  while (1)
7835  {
7836  rv = pthread_mutex_lock (&thread_info_p->mtx);
7837  while (thread_info_p->io_type == FILEIO_WRITE)
7838  {
7839  pthread_cond_wait (&thread_info_p->rcv, &thread_info_p->mtx);
7840  }
7841 
7842  if (thread_info_p->io_type == FILEIO_ERROR_INTERRUPT)
7843  {
7844  need_unlock = true;
7845  node_p = NULL;
7846  goto exit_on_error;
7847  }
7848 
7849  /* get one page from queue head and do write */
7850  if (node_p)
7851  {
7852  node_p->writeable = true;
7853  thread_info_p->io_type = FILEIO_WRITE;
7854  pthread_cond_signal (&thread_info_p->wcv); /* wake up write thread */
7855  while (thread_info_p->io_type == FILEIO_WRITE)
7856  {
7857  pthread_cond_wait (&thread_info_p->rcv, &thread_info_p->mtx);
7858  }
7859 
7860  if (thread_info_p->io_type == FILEIO_ERROR_INTERRUPT)
7861  {
7862  need_unlock = true;
7863  node_p = NULL;
7864  goto exit_on_error;
7865  }
7866  }
7867 
7868  /* check EOF */
7869  if (thread_info_p->pageid >= thread_info_p->from_npages)
7870  {
7871  thread_info_p->end_r_threads++;
7872  if (thread_info_p->end_r_threads >= thread_info_p->act_r_threads)
7873  {
7874  thread_info_p->io_type = FILEIO_WRITE;
7875  pthread_cond_signal (&thread_info_p->wcv); /* wake up write thread */
7876  }
7877  pthread_mutex_unlock (&thread_info_p->mtx);
7878  break;
7879  }
7880 
7881  /* alloc queue node */
7882  node_p = fileio_allocate_node (queue_p, backup_header_p);
7883  if (node_p == NULL)
7884  {
7885  thread_info_p->io_type = FILEIO_ERROR_INTERRUPT;
7886  need_unlock = true;
7887  goto exit_on_error;
7888  }
7889 
7890  /* read one page from Disk sequentially */
7891 
7892  save_area_p = session_p->dbfile.area; /* save link */
7893  session_p->dbfile.area = node_p->area;
7894  node_p->pageid = thread_info_p->pageid;
7895  node_p->writeable = false; /* init */
7896  node_p->nread = fileio_read_backup (thread_p, session_p, node_p->pageid);
7897  session_p->dbfile.area = save_area_p; /* restore link */
7898  if (node_p->nread == -1)
7899  {
7900  thread_info_p->io_type = FILEIO_ERROR_INTERRUPT;
7901  need_unlock = true;
7902  goto exit_on_error;
7903  }
7904  else if (node_p->nread == 0)
7905  {
7906  /* This could be an error since we estimated more pages. End of file/volume. */
7907  thread_info_p->io_type = FILEIO_ERROR_INTERRUPT;
7908  need_unlock = true;
7909  goto exit_on_error;
7910  }
7911 
7912  /* Have to allow other threads to run and check for interrupts from the user (i.e. Ctrl-C ) */
7913  if ((thread_info_p->pageid % FILEIO_CHECK_FOR_INTERRUPT_INTERVAL) == 0
7914  && pgbuf_is_log_check_for_interrupts (thread_p) == true)
7915  {
7916 #if defined(CUBRID_DEBUG)
7917  fprintf (stdout, "io_backup_volume_read interrupt\n");
7918 #endif /* CUBRID_DEBUG */
7919  thread_info_p->io_type = FILEIO_ERROR_INTERRUPT;
7920  need_unlock = true;
7921  goto exit_on_error;
7922  }
7923 
7924  /*
7925  * Do we need to backup this page ?
7926  * In other words, has it been changed since either the previous backup
7927  * of this level or a lower level.
7928  */
7929 
7930  if (thread_info_p->only_updated_pages == false || LSA_ISNULL (&session_p->dbfile.lsa)
7931  || LSA_LT (&session_p->dbfile.lsa, &node_p->area->iopage.prv.lsa))
7932  {
7933  /* Backup the content of this page along with its page identifier add alloced node to the queue */
7934  (void) fileio_append_queue (queue_p, node_p);
7935  }
7936  else
7937  {
7938  /* free node */
7939  (void) fileio_free_node (queue_p, node_p);
7940  node_p = NULL;
7941  }
7942 
7943 #if defined(CUBRID_DEBUG)
7944  fprintf (stdout, "read_thread from_npages = %d, pageid = %d\n", thread_info_p->from_npages,
7945  thread_info_p->pageid);
7946 #endif /* CUBRID_DEBUG */
7947  thread_info_p->pageid++;
7948  pthread_mutex_unlock (&thread_info_p->mtx);
7949  if (node_p)
7950  {
7952  FILEIO_SET_BACKUP_PAGE_ID_COPY (node_p->area, node_p->pageid, backup_header_p->bkpagesize);
7953 
7954 #if defined(CUBRID_DEBUG)
7955  fprintf (stdout, "fileio_read_backup_volume: %d\t%d,\t%d\n",
7956  ((FILEIO_BACKUP_PAGE *) (node_p->area))->iopageid,
7957  *(PAGEID *) (((char *) (node_p->area)) + offsetof (FILEIO_BACKUP_PAGE, iopage) +
7958  backup_header_p->bkpagesize), backup_header_p->bkpagesize);
7959 #endif
7960 
7961  if (backup_header_p->zip_method != FILEIO_ZIP_NONE_METHOD
7962  && fileio_compress_backup_node (node_p, backup_header_p) != NO_ERROR)
7963  {
7964  thread_info_p->io_type = FILEIO_ERROR_INTERRUPT;
7965  need_unlock = false;
7966  node_p = NULL;
7967  goto exit_on_error;
7968  }
7969  }
7970  }
7971 
7972 exit_on_end:
7973 
7974 #if defined(CUBRID_DEBUG)
7975  fprintf (stdout, "end io_backup_volume_read\n");
7976 #endif /* CUBRID_DEBUG */
7977  return;
7978 exit_on_error:
7979 
7980  /* set error info */
7981  if (thread_info_p->errid == NO_ERROR)
7982  {
7983  assert (er_errid () != NO_ERROR);
7984  thread_info_p->errid = er_errid ();
7985  }
7986 
7987  thread_info_p->end_r_threads++;
7988  if (thread_info_p->end_r_threads >= thread_info_p->act_r_threads)
7989  {
7990  pthread_cond_signal (&thread_info_p->wcv); /* wake up write thread */
7991  }
7992 
7993  if (need_unlock)
7994  {
7995  pthread_mutex_unlock (&thread_info_p->mtx);
7996  }
7997 
7998  if (node_p != NULL)
7999  {
8000  (void) fileio_free_node (queue_p, node_p);
8001  }
8002 
8003  goto exit_on_end;
8004 }
8005 
8006 /*
8007  * fileio_write_backup_volume () -
8008  * return:
8009  * session(in/out):
8010  */
8011 static FILEIO_TYPE
8012 fileio_write_backup_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p)
8013 {
8014  FILEIO_THREAD_INFO *thread_info_p;
8015  FILEIO_QUEUE *queue_p;
8016  FILEIO_NODE *node_p;
8017  int rv;
8018  bool need_unlock = false;
8019  FILEIO_BACKUP_HEADER *backup_header_p;
8020  FILEIO_BACKUP_PAGE *save_area_p;
8021 
8022  if (!session_p)
8023  {
8024  return FILEIO_WRITE;
8025  }
8026 
8027  thread_info_p = &session_p->read_thread_info;
8028  queue_p = &thread_info_p->io_queue;
8029 #if defined(CUBRID_DEBUG)
8030  fprintf (stdout, "start io_backup_volume_write\n");
8031 #endif /* CUBRID_DEBUG */
8032  backup_header_p = session_p->bkup.bkuphdr;
8033  rv = pthread_mutex_lock (&thread_info_p->mtx);
8034  while (1)
8035  {
8036  while (thread_info_p->io_type == FILEIO_READ)
8037  {
8038  pthread_cond_wait (&thread_info_p->wcv, &thread_info_p->mtx);
8039  }
8040 
8041  if (thread_info_p->io_type == FILEIO_ERROR_INTERRUPT)
8042  {
8043  need_unlock = true;
8044  goto exit_on_error;
8045  }
8046 
8047  /* do write */
8048  while (queue_p->head && queue_p->head->writeable == true)
8049  {
8050  /* delete the head node of the queue */
8051  node_p = fileio_delete_queue_head (queue_p);
8052  if (node_p == NULL)
8053  {
8054  thread_info_p->io_type = FILEIO_ERROR_INTERRUPT;
8055  }
8056  else
8057  {
8058  save_area_p = session_p->dbfile.area; /* save link */
8059  rv = fileio_write_backup_node (thread_p, session_p, node_p, backup_header_p);
8060  if (rv != NO_ERROR)
8061  {
8062  thread_info_p->io_type = FILEIO_ERROR_INTERRUPT;
8063  }
8064  session_p->dbfile.area = save_area_p; /* restore link */
8065 #if defined(CUBRID_DEBUG)
8066  fprintf (stdout, "write_thread node->pageid = %d, node->nread = %d\n", node_p->pageid, node_p->nread);
8067 #endif /* CUBRID_DEBUG */
8068  if (session_p->verbose_fp && thread_info_p->from_npages >= 25
8069  && node_p->pageid >= thread_info_p->check_npages)
8070  {
8071  fprintf (session_p->verbose_fp, "#");
8072  thread_info_p->check_ratio++;
8073  thread_info_p->check_npages =
8074  (int) (((float) thread_info_p->from_npages / 25.0) * thread_info_p->check_ratio);
8075  }
8076 
8077  /* free node */
8078  (void) fileio_free_node (queue_p, node_p);
8079  }
8080 
8081  if (thread_info_p->io_type == FILEIO_ERROR_INTERRUPT)
8082  {
8083  need_unlock = true;
8084  goto exit_on_error;
8085  }
8086  }
8087 
8088  thread_info_p->io_type = FILEIO_READ; /* reset */
8089  /* check EOF */
8090  if (thread_info_p->end_r_threads >= thread_info_p->act_r_threads)
8091  {
8092  /* only write thread alive */
8093  pthread_mutex_unlock (&thread_info_p->mtx);
8094  break;
8095  }
8096 
8097  pthread_cond_broadcast (&thread_info_p->rcv); /* wake up all read threads */
8098  }
8099 
8100 #if defined(CUBRID_DEBUG)
8101  fprintf (stdout, "end io_backup_volume_write\n");
8102 #endif /* CUBRID_DEBUG */
8103 exit_on_end:
8104 
8105  return thread_info_p->io_type;
8106 exit_on_error:
8107 
8108  /* set error info */
8109  if (er_errid () == NO_ERROR)
8110  {
8111  switch (thread_info_p->errid)
8112  {
8113  case ER_INTERRUPTED:
8115  break;
8116  default: /* give up to handle this case */
8118  fileio_get_base_file_name (backup_header_p->db_fullname));
8119  break;
8120  }
8121  }
8122 
8123  if (thread_info_p->end_r_threads >= thread_info_p->act_r_threads)
8124  {
8125  /* only write thread alive an error (i.e, INTERRUPT) was broken out, so terminate the all threads. But, I am the
8126  * last one, and all the readers are terminated */
8127  pthread_mutex_unlock (&thread_info_p->mtx);
8128  goto exit_on_end;
8129  }
8130 
8131  /* wake up all read threads and wait for all killed */
8132  pthread_cond_broadcast (&thread_info_p->rcv);
8133  pthread_cond_wait (&thread_info_p->wcv, &thread_info_p->mtx);
8134  pthread_mutex_unlock (&thread_info_p->mtx);
8135  goto exit_on_end;
8136 }
8137 
8138 // *INDENT-OFF*
8139 static void
8140 fileio_read_backup_volume_execute (cubthread::entry &thread_ref, FILEIO_BACKUP_SESSION *back_session)
8141 {
8142  fileio_read_backup_volume (&thread_ref, back_session);
8143 }
8144 // *INDENT-ON*
8145 
8146 static int
8147 fileio_start_backup_thread (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p,
8148  FILEIO_THREAD_INFO * thread_info_p, int from_npages, bool is_only_updated_pages,
8149  int check_ratio, int check_npages, FILEIO_QUEUE * queue_p)
8150 {
8151  CSS_CONN_ENTRY *conn_p;
8152  int i;
8153 
8154  /* Initialize global MT variables */
8155  thread_info_p->end_r_threads = 0;
8156  thread_info_p->pageid = 0;
8157  thread_info_p->from_npages = from_npages;
8158  thread_info_p->io_type = FILEIO_READ;
8159  thread_info_p->errid = NO_ERROR;
8160  thread_info_p->only_updated_pages = is_only_updated_pages;
8161  thread_info_p->check_ratio = check_ratio;
8162  thread_info_p->check_npages = check_npages;
8163  thread_info_p->tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
8164  /* start read threads */
8165  conn_p = css_get_current_conn_entry ();
8166  for (i = 1; i <= thread_info_p->act_r_threads; i++)
8167  {
8168  // *INDENT-OFF
8169  auto exec_f = std::bind (fileio_read_backup_volume_execute, std::placeholders::_1, session_p);
8171  // *INDENT-ON
8172  }
8173 
8174  /* work as write thread */
8175  (void) fileio_write_backup_volume (thread_p, session_p);
8176  /* at here, finished all read threads check error, interrupt */
8177  if (thread_info_p->io_type == FILEIO_ERROR_INTERRUPT || queue_p->size != 0)
8178  {
8179  return ER_FAILED;
8180  }
8181 
8182  return NO_ERROR;
8183 }
8184 #endif /* SERVER_MODE */
8185 
8186 #if !defined(CS_MODE)
8187 /*
8188  * fileio_backup_volume () - Include the given database volume/file as part of
8189  * the backup
8190  * return:
8191  * session(in/out): The session array
8192  * from_vlabel(in): Name of the database volume/file to include
8193  * from_volid(in): Identifier of the database volume/file to include
8194  * last_page(in): stop backing up this volume after this page
8195  * only_updated_pages(in): If we are backing up the database with a specific
8196  * backup level. We may opt to backup only the
8197  * updated pages since previous backup.
8198  *
8199  * Note: Information about the database volume/file is recorded, so it
8200  * can be recreated (e.g., name and space).
8201  * If this is an incremental backup, only pages that have been
8202  * updated since the previous backup are backed up, unless a
8203  * specific request is given to backup all pages.
8204  * Last_page can shorten the number of pages saved (i.e. for
8205  * temp volumes, we do not need to backup the entire volume).
8206  *
8207  * 1) The pages are backed up as they are currently stored on disk,
8208  * that is, we do not use the page buffer pool for this operation
8209  * since we do not want to disturbe the normal access patern of
8210  * clients in the page buffer pool.
8211  * 2) We open the file/volume instead of using the actual vdes, so
8212  * that we avoid a bunch of lseeks.
8213  */
8214 int
8215 fileio_backup_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p, const char *from_vol_label_p,
8216  VOLID from_vol_id, PAGEID last_page, bool is_only_updated_pages)
8217 {
8218  struct stat from_stbuf;
8219  int from_npages, npages;
8220  int page_id;
8221  int nread;
8222  FILEIO_BACKUP_FILE_HEADER *file_header_p;
8223  int check_ratio = 0;
8224  int check_npages = 0;
8225  FILEIO_THREAD_INFO *thread_info_p;
8226  FILEIO_QUEUE *queue_p = NULL;
8227  FILEIO_BACKUP_PAGE *save_area_p;
8228  FILEIO_NODE *node_p = NULL;
8229  FILEIO_BACKUP_HEADER *backup_header_p;
8230  int rv;
8231  bool is_need_vol_closed;
8232 
8233 #if (defined(WINDOWS) || !defined(SERVER_MODE))
8234  off_t saved_act_log_fp = (off_t) - 1;
8235 #endif /* WINDOWS || !SERVER_MODE */
8236 
8237  /*
8238  * Backup the pages as they are stored on disk (i.e., don't care if they
8239  * are stored on the page buffer pool any longer). We do not use the page
8240  * buffer pool since we do not want to remove important pages that are
8241  * used by clients.
8242  * We also open the file/volume instead of using the one currently
8243  * available since we do not want to be doing a lot of seeks.
8244  * Remember that we can be preempted.
8245  */
8246  session_p->dbfile.vlabel = from_vol_label_p;
8247  session_p->dbfile.volid = from_vol_id;
8248  session_p->dbfile.vdes = NULL_VOLDES;
8249  is_need_vol_closed = false;
8250  if (from_vol_id == LOG_DBLOG_ACTIVE_VOLID)
8251  {
8253 #if (defined(WINDOWS) || !defined(SERVER_MODE))
8254  if (session_p->dbfile.vdes != NULL_VOLDES)
8255  {
8256  /* save current file pointer */
8257  saved_act_log_fp = lseek (session_p->dbfile.vdes, (off_t) 0, SEEK_CUR);
8258  /* reset file pointer */
8259  if (saved_act_log_fp == (off_t) - 1)
8260  {
8262  goto error;
8263  }
8264 
8265  if (lseek (session_p->dbfile.vdes, (off_t) 0, SEEK_SET) == (off_t) - 1)
8266  {
8268  goto error;
8269  }
8270  }
8271 #endif /* WINDOWS || !SERVER_MODE */
8272  }
8273 
8274  if (session_p->dbfile.vdes == NULL_VOLDES)
8275  {
8276  session_p->dbfile.vdes = fileio_open (session_p->dbfile.vlabel, O_RDONLY, 0);
8277  if (session_p->dbfile.vdes == NULL_VOLDES)
8278  {
8280  goto error;
8281  }
8282  is_need_vol_closed = true;
8283  }
8284 
8285  if (fstat (session_p->dbfile.vdes, &from_stbuf) == -1)
8286  {
8288  goto error;
8289  }
8290 
8291  if (S_ISREG (from_stbuf.st_mode))
8292  {
8293  /* regular file */
8294  session_p->dbfile.nbytes = from_stbuf.st_size;
8295  }
8296  else
8297  {
8298  /* raw device??? */
8299  session_p->dbfile.nbytes = (INT64) xdisk_get_total_numpages (thread_p, from_vol_id) * (INT64) IO_PAGESIZE;
8300  }
8301 
8302  /* print the number divided by volume pagesize */
8303  npages = (int) CEIL_PTVDIV (session_p->dbfile.nbytes, IO_PAGESIZE);
8304  backup_header_p = session_p->bkup.bkuphdr;
8305  if (session_p->verbose_fp)
8306  {
8307  fprintf (session_p->verbose_fp, " %-28s | %10d | ", fileio_get_base_file_name (from_vol_label_p), npages);
8308  }
8309 
8310  /* set the number divied by backup pagesize */
8311  if (last_page >= 0 && last_page < npages)
8312  {
8313  from_npages = CEIL_PTVDIV ((last_page + 1) * IO_PAGESIZE, backup_header_p->bkpagesize);
8314  }
8315  else
8316  {
8317  from_npages = (int) CEIL_PTVDIV (session_p->dbfile.nbytes, backup_header_p->bkpagesize);
8318  }
8319 
8320  /* Write a backup file header which identifies this volume/file on the backup. File headers do not use the extra
8321  * pageid_copy field. */
8323  file_header_p = (FILEIO_BACKUP_FILE_HEADER *) (&session_p->dbfile.area->iopage);
8324  file_header_p->volid = session_p->dbfile.volid;
8325  file_header_p->nbytes = session_p->dbfile.nbytes;
8326  strncpy (file_header_p->vlabel, session_p->dbfile.vlabel, PATH_MAX);
8328  if (fileio_write_backup (thread_p, session_p, nread) != NO_ERROR)
8329  {
8330  goto error;
8331  }
8332 
8333 
8334 #if defined(CUBRID_DEBUG)
8335  /* How about adding a backup verbose option ... to print this sort of information as the backup is progressing? A DBA
8336  * could later compare the information thus gathered with a restore -t option to verify the integrity of the archive. */
8337  if (io_Bkuptrace_debug > 0)
8338  {
8340  file_header_p->vlabel, file_header_p->volid, file_header_p->nbytes, CEIL_PTVDIV (file_header_p->nbytes,
8341  IO_PAGESIZE));
8342  fprintf (stdout, "\n");
8343  }
8344 #endif /* CUBRID_DEBUG */
8345 
8346  /* Now start reading each page and writing each page to the backup. */
8347  if (session_p->verbose_fp)
8348  {
8349  check_ratio = 1;
8350  check_npages = (int) (((float) from_npages / 25.0) * check_ratio);
8351  }
8352 
8353  thread_info_p = &session_p->read_thread_info;
8354  queue_p = &thread_info_p->io_queue;
8355  /* set the number of activated read threads */
8356  thread_info_p->act_r_threads = MAX (thread_info_p->num_threads - 1, 0);
8357  thread_info_p->act_r_threads = MIN (thread_info_p->act_r_threads, from_npages);
8358  if (thread_info_p->act_r_threads > 0)
8359  {
8360 #if defined(SERVER_MODE)
8361  if (fileio_start_backup_thread (thread_p, session_p, thread_info_p, from_npages, is_only_updated_pages,
8362  check_ratio, check_npages, queue_p) != NO_ERROR)
8363  {
8364  goto error;
8365  }
8366 
8367  if (session_p->verbose_fp)
8368  {
8369  check_ratio = thread_info_p->check_ratio;
8370  }
8371 #endif /* SERVER_MODE */
8372  }
8373  else
8374  {
8375  for (page_id = 0; page_id < from_npages; page_id++)
8376  {
8377  /* Have to allow other threads to run and check for interrupts from the user (i.e. Ctrl-C ). check for
8378  * standalone-mode too. */
8379  if ((page_id % FILEIO_CHECK_FOR_INTERRUPT_INTERVAL) == 0
8380  && pgbuf_is_log_check_for_interrupts (thread_p) == true)
8381  {
8382  goto error;
8383  }
8384 
8385  /* alloc queue node */
8386  node_p = fileio_allocate_node (queue_p, backup_header_p);
8387  if (node_p == NULL)
8388  {
8389  goto error;
8390  }
8391 
8392  /* read one page sequentially */
8393  save_area_p = session_p->dbfile.area; /* save link */
8394  session_p->dbfile.area = node_p->area;
8395  node_p->pageid = page_id;
8396  node_p->nread = fileio_read_backup (thread_p, session_p, node_p->pageid);
8397  session_p->dbfile.area = save_area_p; /* restore link */
8398  if (node_p->nread == -1)
8399  {
8400  goto error;
8401  }
8402  else if (node_p->nread == 0)
8403  {
8404  /* This could be an error since we estimated more pages. End of file/volume. */
8405  (void) fileio_free_node (queue_p, node_p);
8406  node_p = NULL;
8407  break;
8408  }
8409 
8410  /*
8411  * Do we need to backup this page ?
8412  * In other words, has it been changed since either the previous backup
8413  * of this level or a lower level.
8414  */
8415 
8416  if (is_only_updated_pages == false || LSA_ISNULL (&session_p->dbfile.lsa)
8417  || LSA_LT (&session_p->dbfile.lsa, &node_p->area->iopage.prv.lsa))
8418  {
8419  /* Backup the content of this page along with its page identifier */
8420 
8422  FILEIO_SET_BACKUP_PAGE_ID_COPY (node_p->area, node_p->pageid, backup_header_p->bkpagesize);
8423 
8424 #if defined(CUBRID_DEBUG)
8425  fprintf (stdout, "fileio_backup_volume: %d\t%d,\t%d\n", ((FILEIO_BACKUP_PAGE *) (node_p->area))->iopageid,
8426  *(PAGEID *) (((char *) (node_p->area)) + offsetof (FILEIO_BACKUP_PAGE, iopage) +
8427  backup_header_p->bkpagesize), backup_header_p->bkpagesize);
8428 #endif
8429 
8430  if (backup_header_p->zip_method != FILEIO_ZIP_NONE_METHOD
8431  && fileio_compress_backup_node (node_p, backup_header_p) != NO_ERROR)
8432  {
8433  goto error;
8434  }
8435 
8436  save_area_p = session_p->dbfile.area; /* save link */
8437  rv = fileio_write_backup_node (thread_p, session_p, node_p, backup_header_p);
8438  session_p->dbfile.area = save_area_p; /* restore link */
8439  if (rv != NO_ERROR)
8440  {
8441  goto error;
8442  }
8443  }
8444 
8445  if (session_p->verbose_fp && from_npages >= 25 && page_id >= check_npages)
8446  {
8447  fprintf (session_p->verbose_fp, "#");
8448  check_ratio++;
8449  check_npages = (int) (((float) from_npages / 25.0) * check_ratio);
8450  }
8451 
8452  /* free node */
8453  (void) fileio_free_node (queue_p, node_p);
8454  node_p = NULL;
8455  }
8456  }
8457 
8458  /* End of FILE */
8459 
8460  /* alloc queue node */
8461  node_p = fileio_allocate_node (queue_p, backup_header_p);
8462  if (node_p == NULL)
8463  {
8464  goto error;
8465  }
8466 
8467  node_p->nread = FILEIO_DBVOLS_IO_PAGE_SIZE (backup_header_p);
8468  memset (&node_p->area->iopage, '\0', backup_header_p->bkpagesize);
8470 
8471 #if defined(CUBRID_DEBUG)
8472  fprintf (stdout, "io_backup_volume: %d\t%d,\t%d\n", ((FILEIO_BACKUP_PAGE *) (node_p->area))->iopageid,
8473  *(PAGEID *) (((char *) (node_p->area)) + offsetof (FILEIO_BACKUP_PAGE, iopage) +
8474  backup_header_p->bkpagesize), backup_header_p->bkpagesize);
8475 #endif
8476 
8477  if (backup_header_p->zip_method != FILEIO_ZIP_NONE_METHOD
8478  && fileio_compress_backup_node (node_p, backup_header_p) != NO_ERROR)
8479  {
8480  goto error;
8481  }
8482 
8483  save_area_p = session_p->dbfile.area; /* save link */
8484  rv = fileio_write_backup_node (thread_p, session_p, node_p, backup_header_p);
8485  session_p->dbfile.area = save_area_p; /* restore link */
8486  if (rv != NO_ERROR)
8487  {
8488  goto error;
8489  }
8490 
8491  /* free node */
8492  (void) fileio_free_node (queue_p, node_p);
8493  node_p = NULL;
8494 #if defined(CUBRID_DEBUG)
8495  fprintf (stdout, "volume EOF : bkpagesize = %d, voltotalio = %ld\n", backup_header_p->bkpagesize,
8496  session_p->bkup.voltotalio);
8497 #endif /* CUBRID_DEBUG */
8498  /* Close the database volume/file */
8499  if (is_need_vol_closed == true)
8500  {
8501  fileio_close (session_p->dbfile.vdes);
8502  }
8503 #if (defined(WINDOWS) || !defined(SERVER_MODE))
8504  else
8505  {
8506  if (from_vol_id == LOG_DBLOG_ACTIVE_VOLID && session_p->dbfile.vdes != NULL_VOLDES && saved_act_log_fp >= 0)
8507  {
8508  /* restore file pointer */
8509  lseek (session_p->dbfile.vdes, saved_act_log_fp, SEEK_SET);
8510  }
8511  }
8512 #endif /* WINDOWS || !SERVER_MODE */
8513 
8514  session_p->dbfile.vdes = NULL_VOLDES;
8515  session_p->dbfile.volid = NULL_VOLID;
8516  session_p->dbfile.nbytes = -1;
8517  session_p->dbfile.vlabel = NULL;
8518  if (session_p->verbose_fp)
8519  {
8520  if (from_npages < 25)
8521  {
8522  fprintf (session_p->verbose_fp, "######################### | done\n");
8523  }
8524  else
8525  {
8526  while (check_ratio <= 25)
8527  {
8528  fprintf (session_p->verbose_fp, "#");
8529  check_ratio++;
8530  }
8531  fprintf (session_p->verbose_fp, " | done\n");
8532  }
8533  }
8534 
8535  return NO_ERROR;
8536 
8537 error:
8538  if (is_need_vol_closed == true)
8539  {
8540  fileio_close (session_p->dbfile.vdes);
8541  }
8542 #if (defined(WINDOWS) || !defined(SERVER_MODE))
8543  else
8544  {
8545  if (from_vol_id == LOG_DBLOG_ACTIVE_VOLID && session_p->dbfile.vdes != NULL_VOLDES && saved_act_log_fp >= 0)
8546  {
8547  /* restore file pointer */
8548  lseek (session_p->dbfile.vdes, saved_act_log_fp, SEEK_SET);
8549  }
8550  }
8551 #endif /* WINDOWS || !SERVER_MODE */
8552 
8553  if (node_p != NULL)
8554  {
8555  (void) fileio_free_node (queue_p, node_p);
8556  }
8557 
8558  session_p->dbfile.vdes = NULL_VOLDES;
8559  session_p->dbfile.volid = NULL_VOLID;
8560  session_p->dbfile.nbytes = -1;
8561  session_p->dbfile.vlabel = NULL;
8562  return ER_FAILED;
8563 }
8564 #endif /* !CS_MODE */
8565 
8566 /*
8567  * fileio_flush_backup () - Flush any buffered data
8568  * return:
8569  * session(in/out): The session array
8570  *
8571  * Note: When the output fills up, we prompt for another volume or more space.
8572  * Incomplete blocks are repeated at the start of the following archive,
8573  * in order to insure that we do not try to read from incomplete tape
8574  * blocks.
8575  */
8576 static int
8578 {
8579  char *buffer_p;
8580  ssize_t nbytes;
8581  INT64 count;
8582  bool is_interactive_need_new = false;
8583  bool is_force_new_bkvol = false;
8584 
8587  {
8588  er_log_debug (ARG_FILE_LINE, "Backup_flush: Backup aborted because count %d larger than max volume size %ld\n",
8590  return ER_FAILED;
8591  }
8592 
8593 #if defined(CUBRID_DEBUG)
8594  fprintf (stdout, "io_backup_flush: bkup.count = %ld, voltotalio = %ld\n", session_p->bkup.count,
8595  session_p->bkup.voltotalio);
8596 #endif /* CUBRID_DEBUG */
8597  /*
8598  * Flush any buffered bytes.
8599  * NOTE that we do not call fileio_write since it will try to do lseek and some
8600  * backup devices do not seek.
8601  */
8602  if (session_p->bkup.count > 0)
8603  {
8604  restart_newvol:
8605  /*
8606  * Determine number of bytes we can safely write to this volume
8607  * being mindful of the max specified by the user.
8608  */
8609  is_interactive_need_new = false;
8610  is_force_new_bkvol = false;
8611  count = session_p->bkup.count;
8613  {
8614  count =
8615  (int) MIN (count, prm_get_bigint_value (PRM_ID_IO_BACKUP_MAX_VOLUME_SIZE) - session_p->bkup.voltotalio);
8616  }
8617  buffer_p = session_p->bkup.buffer;
8618  do
8619  {
8620  /* disk file size check */
8621 
8622 
8623  if (session_p->bkup.voltotalio >= OFF_T_MAX && session_p->bkup.dtype == FILEIO_BACKUP_VOL_DIRECTORY)
8624  {
8625  /* New volume is needed */
8626  is_force_new_bkvol = true;
8627  }
8628  else
8629  {
8630  /* Write the data */
8631  nbytes = write (session_p->bkup.vdes, buffer_p, count);
8632  if (nbytes <= 0)
8633  {
8634  if (nbytes == 0)
8635  {
8636  is_interactive_need_new = true; /* For raw partitions */
8637  }
8638  else
8639  {
8640  switch (errno)
8641  {
8642  /* equiv to try again */
8643  case EINTR:
8644  case EAGAIN:
8645  continue;
8646  /* New volume is needed and no user interaction needed */
8647 #if !defined(WINDOWS)
8648  case EDQUOT:
8649 #endif /* !WINDOWS */
8650  case EFBIG:
8651  case EIO:
8652  case EINVAL:
8653  is_force_new_bkvol = true;
8654  break;
8655  /* New volume is needed and requires user interaction */
8656  case ENXIO:
8657  case ENOSPC:
8658  case EPIPE:
8659  is_interactive_need_new = true;
8660  break;
8661  /* equiv -- Failure */
8662  default:
8664  CEIL_PTVDIV (session_p->bkup.voltotalio, IO_PAGESIZE),
8665  session_p->bkup.vlabel);
8666  return ER_FAILED;
8667  }
8668  }
8669  }
8670  else
8671  {
8672  session_p->bkup.voltotalio += nbytes;
8673  count -= (int) nbytes;
8674  buffer_p += nbytes;
8675  }
8676  }
8677 
8678  if (is_interactive_need_new || is_force_new_bkvol
8681  {
8682 #if defined(CUBRID_DEBUG)
8683  fprintf (stdout, "open a new backup volume\n");
8684 #endif /* CUBRID_DEBUG */
8685  /* Finish this volume, fixup session and open a new volume */
8686  if ((fileio_get_next_backup_volume (thread_p, session_p, is_interactive_need_new) != NO_ERROR)
8687  || (fileio_write_backup_header (session_p) != NO_ERROR))
8688  {
8689  return ER_FAILED;
8690  }
8691  else
8692  {
8693  /* Because the buffer may have been incompletely written on a raw device (i.e. tape), we start a new
8694  * volume by repeating the current buffer block in its entirety immediately after the header. Upon
8695  * restore, the incomplete part will be ignored. */
8696  session_p->bkup.ptr = session_p->bkup.buffer;
8697  goto restart_newvol;
8698  }
8699  }
8700  }
8701  while (count > 0);
8702  /* Update session to reflect that flush completed. */
8703  session_p->bkup.count = 0; /* can only update after flush completes */
8704  session_p->bkup.ptr = session_p->bkup.buffer;
8705  }
8706 
8707  return NO_ERROR;
8708 }
8709 
8710 /*
8711  * fileio_read_backup () - Read a database page from the current database
8712  * volume/file that is backed up
8713  * return:
8714  * session(in/out): The session array
8715  * pageid(in): The page from which we are reading
8716  *
8717  * Note: If we run into an end of file, we filled the page with nulls. This is
8718  * needed since we write full pages to back up destination. Without this,
8719  * we will not be able to know how much to read since not necessarily
8720  * the whole volume/file is backed up.
8721  */
8722 static ssize_t
8723 fileio_read_backup (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p, int page_id)
8724 {
8725  int io_page_size = session_p->bkup.bkuphdr->bkpagesize;
8726 #if defined(WINDOWS)
8727  int nread, nbytes;
8728 #else
8729  ssize_t nread, nbytes;
8730 #endif
8731  char *buffer_p;
8732 
8733  /* Read until you acumulate io_pagesize or the EOF mark is reached. */
8734  nread = 0;
8735  FILEIO_SET_BACKUP_PAGE_ID (session_p->dbfile.area, page_id, io_page_size);
8736 
8737 #if defined(CUBRID_DEBUG)
8738  fprintf (stdout, "fileio_read_backup: %d\t%d,\t%d\n", ((FILEIO_BACKUP_PAGE *) (session_p->dbfile.area))->iopageid,
8739  *(PAGEID *) (((char *) (session_p->dbfile.area)) + offsetof (FILEIO_BACKUP_PAGE, iopage) + io_page_size),
8740  io_page_size);
8741 #endif
8742 
8743  buffer_p = (char *) &session_p->dbfile.area->iopage;
8744  while (nread < io_page_size)
8745  {
8746  /* Read the desired amount of bytes */
8747 #if !defined(SERVER_MODE)
8748  nbytes = read (session_p->dbfile.vdes, buffer_p, io_page_size - nread);
8749 #elif defined(WINDOWS)
8750  nbytes = read (session_p->dbfile.vdes, buffer_p, io_page_size - nread);
8751 #else
8752  nbytes =
8753  pread (session_p->dbfile.vdes, buffer_p, io_page_size - nread,
8754  FILEIO_GET_FILE_SIZE (io_page_size, page_id) + nread);
8755 #endif
8756  if (nbytes == -1)
8757  {
8758  if (errno != EINTR)
8759  {
8761  FILEIO_GET_BACKUP_PAGE_ID (session_p->dbfile.area), session_p->dbfile.vlabel);
8762  return -1;
8763  }
8764  }
8765  else if (nbytes == 0)
8766  {
8767  if (nread > 0)
8768  {
8769 #if defined(CUBRID_DEBUG)
8770  fprintf (stdout, "io_backup_read: io_pagesize = %d, nread = %d, voltotalio = %d : ADD FILLER\n",
8771  io_page_size, nread, session_p->bkup.voltotalio);
8772 #endif /* CUBRID_DEBUG */
8773  /*
8774  * We have a file that it is not multiples of io_pagesize.
8775  * We need to add a filler. otherwise, we will not be able to
8776  * find other files.
8777  */
8778  memset (buffer_p, '\0', io_page_size - nread);
8779  nread = io_page_size;
8780  }
8781  break;
8782  }
8783  nread += nbytes;
8784  buffer_p += nbytes;
8785  }
8786 
8787 #if defined(SERVER_MODE)
8788  /* Backup Thread is reading data/log pages slowly to avoid IO burst */
8789  if (session_p->dbfile.volid == LOG_DBLOG_ACTIVE_VOLID
8790  || (session_p->dbfile.volid == LOG_DBLOG_ARCHIVE_VOLID && LOG_CS_OWN_WRITE_MODE (thread_p)))
8791  {
8792  ; /* go ahead */
8793  }
8794  else
8795  {
8796  int sleep_msecs;
8797 
8798  if (session_p->sleep_msecs > 0) /* priority 1 */
8799  {
8800  sleep_msecs = session_p->sleep_msecs;
8801  }
8802  else if (prm_get_integer_value (PRM_ID_IO_BACKUP_SLEEP_MSECS) > 0) /* priority 2 */
8803  {
8805  }
8806  else
8807  {
8808  sleep_msecs = 0;
8809  }
8810 
8811  if (sleep_msecs > 0)
8812  {
8813  sleep_msecs = (int) (((double) sleep_msecs) / (ONE_M / io_page_size));
8814 
8815  if (sleep_msecs > 0)
8816  {
8817  thread_sleep (sleep_msecs);
8818  }
8819  }
8820  }
8821 #endif
8822 
8823  return nread;
8824 }
8825 
8826 /*
8827  * fileio_write_backup () - Write the number of indicated bytes from the dbfile
8828  * area to to the backup destination
8829  * return:
8830  * session(in/out): The session array
8831  * towrite_nbytes(in): Number of bytes that must be written
8832  */
8833 static int
8834 fileio_write_backup (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p, ssize_t to_write_nbytes)
8835 {
8836  char *buffer_p;
8837  ssize_t nbytes;
8838 
8839  buffer_p = (char *) session_p->dbfile.area;
8840  while (to_write_nbytes > 0)
8841  {
8842  /*
8843  * Buffer as much as you can, so that the device I/O will go through
8844  * without any problem. Remember some backup devices work only with
8845  * a fixed I/O length. We cannot use io_backup_write because we may
8846  * have been called recursively from there after the old volume filled.
8847  */
8848  nbytes = CAST_BUFLEN (session_p->bkup.iosize - session_p->bkup.count);
8849  if (nbytes > to_write_nbytes)
8850  {
8851  nbytes = to_write_nbytes;
8852  }
8853 
8854  memcpy (session_p->bkup.ptr, buffer_p, nbytes);
8855  session_p->bkup.count += nbytes;
8856  session_p->bkup.ptr += nbytes;
8857  buffer_p += nbytes;
8858  to_write_nbytes -= nbytes;
8859  if (session_p->bkup.count >= session_p->bkup.iosize)
8860  {
8861  if (fileio_flush_backup (thread_p, session_p) != NO_ERROR)
8862  {
8863  return ER_FAILED;
8864  }
8865  }
8866  }
8867 
8868  return NO_ERROR;
8869 }
8870 
8871 /*
8872  * fileio_write_backup_header () - Immediately write the backup header to the
8873  * destination
8874  * return:
8875  * session(in/out): The session array
8876  *
8877  * Note: Note that unlike io_backup_write, we do not buffer, instead we
8878  * write directly to the output destination the number of bytes
8879  * in a bkuphdr. This insures that headers all have the same
8880  * physical block size so we can read them properly. The main
8881  * purpose of this routine is to write the headers in a tape
8882  * friendly blocking factor such that we can be sure we can read
8883  * them back in without knowing how the tape was written in the
8884  * first place.
8885  */
8886 static int
8888 {
8889  char *buffer_p;
8890  int count, nbytes;
8891 
8892  /* Write immediately to the backup. We do not use fileio_write for the same reason io_backup_flush does not. */
8894  buffer_p = (char *) session_p->bkup.bkuphdr;
8895  do
8896  {
8897  nbytes = write (session_p->bkup.vdes, buffer_p, count);
8898  if (nbytes == -1)
8899  {
8900  if (errno == EINTR || errno == EAGAIN)
8901  {
8902  continue;
8903  }
8904 
8905  if (errno == ENOSPC)
8906  {
8908  CEIL_PTVDIV (session_p->bkup.voltotalio, IO_PAGESIZE),
8910  }
8911  else
8912  {
8914  CEIL_PTVDIV (session_p->bkup.voltotalio, IO_PAGESIZE), session_p->bkup.vlabel);
8915  }
8916  return ER_FAILED;
8917  }
8918  else
8919  {
8920  count -= nbytes;
8921  buffer_p += nbytes;
8922  }
8923  }
8924  while (count > 0);
8926  return NO_ERROR;
8927 }
8928 
8929 /*
8930  * fileio_initialize_restore () - Initialize the restore session structure with the given information
8931  * return: session or NULL
8932  * db_fullname(in): Name of the database to backup
8933  * backup_src(in): Name of backup device (file or directory)
8934  * session(in/out): The session array
8935  * level(in): The presumed backup level
8936  * restore_verbose_file_path(in):
8937  * newvolpath(in): restore the database and log volumes to the path
8938  * specified in the database-loc-file
8939  *
8940  * Note: Note that the user may choose a new location for the volume, so the
8941  * contents of the backup source path may be set as a side effect.
8942  */
8943 static FILEIO_BACKUP_SESSION *
8944 fileio_initialize_restore (THREAD_ENTRY * thread_p, const char *db_full_name_p, char *backup_source_p,
8945  FILEIO_BACKUP_SESSION * session_p, FILEIO_BACKUP_LEVEL level,
8946  const char *restore_verbose_file_path, bool is_new_vol_path)
8947 {
8948  char orig_name[PATH_MAX];
8949 
8950  strcpy (orig_name, backup_source_p);
8951  /* First, make sure the volume given exists and we can access it. */
8952  while (!fileio_is_volume_exist (backup_source_p))
8953  {
8955  fprintf (stdout, "%s\n", er_msg ());
8956  /* Let user see original prompt name until good one is chosen */
8957  strcpy (backup_source_p, orig_name);
8958  if (fileio_find_restore_volume (thread_p, db_full_name_p, backup_source_p, FILEIO_INITIAL_BACKUP_UNITS, level,
8960  {
8961  return NULL;
8962  }
8963  }
8964 
8965  /* Backup session initialization is the same as restore for now, as long as the first backup volume already exists,
8966  * which we just checked. */
8967  session_p->type = FILEIO_BACKUP_READ; /* access backup device for read */
8968  /* save database full-pathname specified in the database-loc-file */
8969  strncpy_bufsize (session_p->bkup.loc_db_fullname, is_new_vol_path ? db_full_name_p : "");
8970  return (fileio_initialize_backup (db_full_name_p, (const char *) backup_source_p, session_p, level,
8971  restore_verbose_file_path, 0 /* no multi-thread */ , 0 /* no sleep */ ));
8972 }
8973 
8974 /*
8975  * fileio_abort_restore () - The restore session is aborted
8976  * return: void
8977  * session(in/out): The session array
8978  */
8979 void
8981 {
8982  fileio_abort_backup (thread_p, session_p, false);
8983 }
8984 
8985 /*
8986  * fileio_read_restore () - The number of bytes to read from the backup destination
8987  * return:
8988  * session(in/out): The session array
8989  * toread_nbytes(in): Number of bytes to read
8990  *
8991  * Note: Now handles reads which span volumes, as well as reading incomplete
8992  * blocks at the end of one volume. See fileio_flush_backup for details
8993  * about how the final block is repeated at the start of the new volumes.
8994  */
8995 static int
8996 fileio_read_restore (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p, int to_read_nbytes)
8997 {
8998 #if defined(WINDOWS)
8999  int nbytes;
9000 #else
9001  ssize_t nbytes;
9002 #endif
9003  char *buffer_p;
9004  const char *next_vol_p;
9005  bool is_end_of_backup = false;
9006  bool is_need_next_vol = false;
9007 
9008  /* Read until you acumulate the desired number of bytes (a database page) or the EOF mark is reached. */
9009  buffer_p = (char *) session_p->dbfile.area;
9010  while (to_read_nbytes > 0 && is_end_of_backup == false)
9011  {
9012  if (session_p->bkup.count <= 0)
9013  {
9014  /*
9015  * Read and buffer another backup page from the backup volume.
9016  * Note that a backup page is not necessarily the same size as the
9017  * database page.
9018  */
9019  restart_newvol:
9020  is_need_next_vol = false;
9021  session_p->bkup.ptr = session_p->bkup.buffer;
9022  session_p->bkup.count = session_p->bkup.iosize;
9023  while (session_p->bkup.count > 0)
9024  {
9025  /* Read a backup I/O page. */
9026  nbytes = read (session_p->bkup.vdes, session_p->bkup.ptr, (int) session_p->bkup.count);
9027  if (nbytes <= 0)
9028  {
9029  /* An error or EOF was found */
9030  if (nbytes == 0)
9031  {
9032  /* Perhaps the last page read in was the very last one */
9034  {
9035  is_end_of_backup = true;
9036  break;
9037  }
9038  else
9039  {
9040  is_need_next_vol = true;
9041  }
9042  }
9043  else
9044  {
9045  switch (errno)
9046  {
9047  case EINTR:
9048  case EAGAIN:
9049  continue;
9050  case EINVAL:
9051  case ENXIO:
9052 #if !defined(WINDOWS)
9053  case EOVERFLOW:
9054 #endif /* !WINDOWS */
9055  is_need_next_vol = true;
9056  break;
9057  default:
9058  {
9059 
9061  CEIL_PTVDIV (session_p->bkup.voltotalio, IO_PAGESIZE),
9062  session_p->bkup.vlabel);
9063  return ER_FAILED;
9064  }
9065  }
9066  }
9067 
9068  if (is_need_next_vol)
9069  {
9070  next_vol_p =
9072  session_p->bkup.bkuphdr->unit_num + 1,
9074  if (next_vol_p == NULL)
9075  {
9076  if (session_p->bkup.dtype != FILEIO_BACKUP_VOL_DEVICE)
9077  {
9078  fileio_get_directory_path (session_p->bkup.current_path, session_p->bkup.vlabel);
9079  next_vol_p = session_p->bkup.current_path;
9080  }
9081  }
9082  else
9083  {
9084  if (!fileio_is_volume_exist (next_vol_p)
9085  && strncmp (next_vol_p, session_p->bkup.current_path,
9086  strlen (session_p->bkup.current_path)) != 0)
9087  {
9088  /* assume the changed path, not bkvinf file */
9089  next_vol_p = session_p->bkup.current_path;
9090  }
9091  }
9092 
9093  /* Unmount current backup volume */
9094  fileio_dismount_without_fsync (thread_p, session_p->bkup.vdes);
9095  session_p->bkup.vdes = NULL_VOLDES;
9096  /* Find and mount the next volume and continue. */
9097  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DEVICE || next_vol_p == NULL)
9098  {
9099  /* Probably a tape device, let user mount new one */
9100  if (next_vol_p != NULL)
9101  {
9102  strncpy (session_p->bkup.name, next_vol_p, PATH_MAX - 1);
9103  }
9104  if (fileio_find_restore_volume (thread_p, session_p->bkup.bkuphdr->db_fullname,
9105  session_p->bkup.name, session_p->bkup.bkuphdr->unit_num + 1,
9106  session_p->bkup.bkuphdr->level,
9108  {
9109  return ER_FAILED;
9110  }
9111  }
9112  else
9113  {
9114  strncpy (session_p->bkup.name, next_vol_p, PATH_MAX - 1);
9115  }
9116 
9117  /* Reset session count, etc */
9118  session_p->bkup.alltotalio += session_p->bkup.voltotalio;
9119  session_p->bkup.voltotalio = 0;
9120  session_p->bkup.count = 0;
9121  /* Bump the unit number to find the next volume */
9122  session_p->bkup.bkuphdr->unit_num++;
9123  /* Open the next volume */
9124  if (fileio_continue_restore (thread_p, session_p->bkup.bkuphdr->db_fullname,
9125  session_p->bkup.bkuphdr->db_creation, session_p, false, true,
9126  session_p->bkup.bkuphdr->start_time) == NULL)
9127  {
9128  return ER_FAILED;
9129  }
9130  /* reset ptr */
9131  session_p->bkup.ptr = session_p->bkup.buffer;
9132  /* add new backup volume info info new_bkvinf */
9133  fileio_add_volume_to_backup_info (session_p->bkup.vlabel, session_p->bkup.bkuphdr->level,
9134  session_p->bkup.bkuphdr->unit_num,
9136  /* Retry the buffered read from the new volume */
9137  goto restart_newvol;
9138  }
9139  }
9140  else
9141  {
9142  /* Increase the amount of read bytes */
9143  session_p->bkup.ptr += nbytes;
9144  session_p->bkup.count -= nbytes;
9145  session_p->bkup.voltotalio += nbytes;
9146  }
9147  }
9148 
9149  /* Increase the buffered information */
9150  session_p->bkup.ptr = session_p->bkup.buffer;
9151  session_p->bkup.count = session_p->bkup.iosize - session_p->bkup.count;
9152  }
9153 
9154  /* Now copy the desired bytes */
9155  nbytes = session_p->bkup.count;
9156  if (nbytes > to_read_nbytes)
9157  {
9158  nbytes = to_read_nbytes;
9159  }
9160  memcpy (buffer_p, session_p->bkup.ptr, nbytes);
9161  session_p->bkup.count -= nbytes;
9162  to_read_nbytes -= nbytes;
9163  session_p->bkup.ptr += nbytes;
9164  buffer_p += nbytes;
9165  }
9166 
9167  if (to_read_nbytes > 0 && !is_end_of_backup)
9168  {
9169  return ER_FAILED;
9170  }
9171  else
9172  {
9173  return NO_ERROR;
9174  }
9175 }
9176 
9177 /*
9178  * fileio_read_restore_header () - READ A BACKUP VOLUME HEADER
9179  * return:
9180  * session(in/out): The session array
9181  *
9182  * Note: This routine should be the first read from a backup volume or device.
9183  * It reads the backup volume header that was written with the
9184  * fileio_write_backup_header routine. The header was written with a
9185  * specific buffer block size to be more compatible with tape devices so
9186  * we can read it in without knowing how the rest of the data was
9187  * buffered. Note this also means that backup volume headers are not the
9188  * same size as FILEIO_BACKUP_PAGE anymore.
9189  */
9190 static int
9192 {
9193  int to_read_nbytes;
9194  int nbytes;
9195  char *buffer_p;
9196  FILEIO_BACKUP_HEADER *backup_header_p;
9197 
9198  backup_header_p = session_p->bkup.bkuphdr;
9199  to_read_nbytes = FILEIO_BACKUP_HEADER_IO_SIZE;
9200  buffer_p = (char *) backup_header_p;
9201  while (to_read_nbytes > 0)
9202  {
9203  nbytes = read (session_p->bkup.vdes, buffer_p, to_read_nbytes);
9204  if (nbytes == -1)
9205  {
9206  if (errno == EINTR)
9207  {
9208  continue;
9209  }
9210  else
9211  {
9213  CEIL_PTVDIV (session_p->bkup.voltotalio, IO_PAGESIZE), session_p->bkup.vlabel);
9214  return ER_FAILED;
9215  }
9216  }
9217  else if (nbytes == 0)
9218  {
9219  /* EOF should not happen when reading the header. */
9221  CEIL_PTVDIV (session_p->bkup.voltotalio, IO_PAGESIZE), session_p->bkup.vlabel);
9222  return ER_FAILED;
9223  }
9224  to_read_nbytes -= nbytes;
9225  session_p->bkup.voltotalio += nbytes;
9226  buffer_p += nbytes;
9227  }
9228 
9229  /* TODO: check for OLD version: no compression */
9230  if (backup_header_p->bk_hdr_version == FILEIO_BACKUP_NO_ZIP_HEADER_VERSION)
9231  {
9232  backup_header_p->bkpagesize = backup_header_p->db_iopagesize;
9233  backup_header_p->zip_method = FILEIO_ZIP_NONE_METHOD;
9234  backup_header_p->zip_level = FILEIO_ZIP_NONE_LEVEL;
9235  }
9236 
9237  if (to_read_nbytes > 0)
9238  {
9239  return ER_FAILED;
9240  }
9241  else
9242  {
9243  return NO_ERROR;
9244  }
9245 }
9246 
9247 /*
9248  * fileio_start_restore () - Start a restore session
9249  * return: session or NULL
9250  * db_fullname(in): Name of the database to backup
9251  * backup_source(in): Name of backup destination device (file or directory)
9252  * match_dbcreation(out): Creation of data base of backup
9253  * db_iopagesize(out): Database size of database in backup
9254  * db_compatibility(out): Disk compatibility of database in backup
9255  * session(in/out): The session array
9256  * level(in): The presumed backup level
9257  * authenticate(in): true when validation of new bkup volume header needed
9258  * match_bkupcreation(in): explicit timestamp to match in new backup volume
9259  * restore_verbose_file_path(in):
9260  * newvolpath(in): restore the database and log volumes to the path
9261  * specified in the database-loc-file
9262  */
9264 fileio_start_restore (THREAD_ENTRY * thread_p, const char *db_full_name_p, char *backup_source_p,
9265  INT64 match_db_creation_time, PGLENGTH * db_io_page_size_p, float *db_compatibility_p,
9266  FILEIO_BACKUP_SESSION * session_p, FILEIO_BACKUP_LEVEL level, bool is_authenticate,
9267  INT64 match_backup_creation_time, const char *restore_verbose_file_path, bool is_new_vol_path)
9268 {
9269  FILEIO_BACKUP_SESSION *temp_session_p;
9270 
9271  /* Initialize the session array and open the backup source device. */
9272  if (fileio_initialize_restore (thread_p, db_full_name_p, backup_source_p, session_p, level,
9273  restore_verbose_file_path, is_new_vol_path) == NULL)
9274  {
9275  return NULL;
9276  }
9277 
9278  temp_session_p =
9279  fileio_continue_restore (thread_p, db_full_name_p, match_db_creation_time, session_p, true, is_authenticate,
9280  match_backup_creation_time);
9281  if (temp_session_p != NULL)
9282  {
9283  *db_io_page_size_p = session_p->bkup.bkuphdr->db_iopagesize;
9284  *db_compatibility_p = session_p->bkup.bkuphdr->db_compatibility;
9285  }
9286 
9287  return (temp_session_p);
9288 }
9289 
9290 static int
9291 fileio_make_error_message (THREAD_ENTRY * thread_p, char *error_message_p)
9292 {
9293  char *header_message_p = NULL;
9294  char *remote_message_p = NULL;
9295 
9296  if (asprintf (&header_message_p, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_IO,
9298  {
9300  return ER_FAILED;
9301  }
9302 
9303  if (asprintf (&remote_message_p, "%s%s", header_message_p, error_message_p) < 0)
9304  {
9306  free (header_message_p);
9307  return ER_FAILED;
9308  }
9309 
9310  (void) fileio_request_user_response (thread_p, FILEIO_PROMPT_DISPLAY_ONLY, remote_message_p, NULL, NULL, -1, -1, NULL,
9311  -1);
9312  free (header_message_p);
9313  free (remote_message_p);
9314  return NO_ERROR;
9315 }
9316 
9317 /*
9318  * fileio_continue_restore () - CONTINUE A RESTORE SESSION
9319  * return: session or NULL
9320  * db_fullname(in): Name of the database to backup
9321  * db_creation(in): Creation of time data base
9322  * session(in/out): The session array
9323  * first_time(in): true the first time called during restore
9324  * authenticate(in): true when validation of new bkup volume header needed
9325  * match_bkupcreation(in): Creation time of backup
9326  *
9327  * Note: Called when a new backup volume is needed, this routine locates and
9328  * opens the desired backup volume for this database. Also authenticates
9329  * that it has the right timestamp, level, unit_num etc.
9330  * The match_dbcreation parameter specifies an explicit bkup timestamp
9331  * that must be matched. This is useful when one level is restored and
9332  * the next is required. A zero for this variable will ignore the test.
9333  */
9334 static FILEIO_BACKUP_SESSION *
9335 fileio_continue_restore (THREAD_ENTRY * thread_p, const char *db_full_name_p, INT64 db_creation_time,
9336  FILEIO_BACKUP_SESSION * session_p, bool is_first_time, bool is_authenticate,
9337  INT64 match_backup_creation_time)
9338 {
9339  FILEIO_BACKUP_HEADER *backup_header_p;
9340  int unit_num = FILEIO_INITIAL_BACKUP_UNITS;
9341  PAGEID expect_page_id;
9342  bool is_need_retry;
9343  bool is_original_header = true;
9344  char *error_message_p = NULL;
9345  struct stat stbuf;
9346  const char *db_nopath_name_p;
9347  char copy_name[PATH_MAX];
9348  char orig_name[PATH_MAX];
9349  FILEIO_BACKUP_LEVEL level;
9350  int exists;
9351  int search_loop_count = 0;
9352  char io_timeval[CTIME_MAX];
9353 
9354  memset (io_timeval, 0, sizeof (io_timeval));
9355 
9356  /* Note that for the first volume to be restored, bkuphdr must have been initialized with sensible defaults for these
9357  * variables. */
9358  unit_num = session_p->bkup.bkuphdr->unit_num;
9359  level = session_p->bkup.bkuphdr->level;
9360  do
9361  {
9362  is_need_retry = false;
9363  /* Have to locate and open the desired volume */
9364  while (session_p->bkup.vdes == NULL_VOLDES)
9365  {
9366 
9367  /* If the name chosen is a actually a directory, then append correct backup volume name here. */
9368  exists = stat (session_p->bkup.vlabel, &stbuf) != -1;
9369  if (session_p->bkup.dtype != FILEIO_BACKUP_VOL_DEVICE && (exists && S_ISDIR (stbuf.st_mode)))
9370  {
9371  db_nopath_name_p = fileio_get_base_file_name (db_full_name_p);
9372  strcpy (copy_name, session_p->bkup.vlabel);
9373  fileio_make_backup_name (session_p->bkup.name, db_nopath_name_p, copy_name, level, unit_num);
9374  session_p->bkup.vlabel = session_p->bkup.name;
9375  }
9376 
9377  if (search_loop_count == 0)
9378  {
9379  strcpy (orig_name, session_p->bkup.vlabel);
9380  }
9381 
9382  session_p->bkup.vdes = fileio_open (session_p->bkup.vlabel, O_RDONLY, 0);
9383  if (session_p->bkup.vdes == NULL_VOLDES)
9384  {
9385 
9387  fprintf (stdout, "%s\n", er_msg ());
9388  /* Since we cannot find what they were just looking for, reset the name to what we started looking for in
9389  * the first place. */
9390  strcpy (session_p->bkup.name, orig_name);
9391  /* Attempt to locate the desired volume */
9392  if (fileio_find_restore_volume (thread_p, db_full_name_p, session_p->bkup.name, unit_num, level,
9394  {
9395  /* Cannot access backup file. Restore from backup is cancelled. */
9397  session_p->bkup.vlabel);
9398  return NULL;
9399  }
9400  }
9401  search_loop_count++;
9402  }
9403 
9404  /* Read description of the backup file. */
9405  if (fileio_read_restore_header (session_p) != NO_ERROR)
9406  {
9408  is_need_retry = true;
9409  goto retry_newvol;
9410  }
9411 
9412  backup_header_p = session_p->bkup.bkuphdr;
9413  /* check for restoring the database and log volumes to the path specified in the database-loc-file */
9414  if (session_p->bkup.loc_db_fullname[0] != '\0')
9415  {
9416  /* replace db_fullname with the databases.txt info */
9417  strncpy (backup_header_p->db_fullname, session_p->bkup.loc_db_fullname, PATH_MAX);
9418  }
9419 
9420  /* Always check for a valid magic number, regardless of whether we need to check other authentications. */
9421  if (strcmp (backup_header_p->magic, CUBRID_MAGIC_DATABASE_BACKUP) != 0)
9422  {
9423  if (strcmp (backup_header_p->magic, CUBRID_MAGIC_DATABASE_BACKUP_OLD) == 0)
9424  {
9426  rel_release_string ());
9427  return NULL;
9428  }
9429 
9430  if (is_first_time)
9431  {
9433  return NULL;
9434  }
9435  else
9436  {
9437  if (asprintf (&error_message_p,
9439  session_p->bkup.vlabel) < 0)
9440  {
9442  return NULL;
9443  }
9444 
9445  if (fileio_make_error_message (thread_p, error_message_p) != NO_ERROR)
9446  {
9447  free (error_message_p);
9448  return NULL;
9449  }
9450 
9451  free (error_message_p);
9452  is_need_retry = true;
9453  goto retry_newvol;
9454  }
9455  }
9456 
9457  /* Should check the release version before we do anything */
9458  if (is_first_time && rel_is_log_compatible (backup_header_p->db_release, rel_release_string ()) != true)
9459  {
9460  /*
9461  * First time this database is restarted using the current version of
9462  * CUBRID. Recovery should be done using the old version of the
9463  * system
9464  */
9466  backup_header_p->db_release, rel_release_string (), rel_release_string ());
9467  return NULL;
9468  }
9469 
9470  if (is_authenticate)
9471  {
9472  if (is_first_time)
9473  {
9474  LSA_COPY (&session_p->dbfile.lsa, &backup_header_p->start_lsa);
9475  }
9476 
9477  if (level != backup_header_p->level)
9478  {
9479  if (asprintf (&error_message_p,
9481  session_p->bkup.vlabel, backup_header_p->level, level) < 0)
9482  {
9484  return NULL;
9485  }
9486 
9487  if (fileio_make_error_message (thread_p, error_message_p) != NO_ERROR)
9488  {
9489  free (error_message_p);
9490  return NULL;
9491  }
9492 
9493  free (error_message_p);
9494  is_need_retry = true;
9495  goto retry_newvol;
9496  }
9497 
9498  /* Test the timestamp of when the backup was taken. */
9499  if (match_backup_creation_time != 0
9500  && difftime ((time_t) match_backup_creation_time, (time_t) backup_header_p->start_time))
9501  {
9502  char save_time1[64];
9503 
9504  fileio_ctime (&match_backup_creation_time, io_timeval);
9505  strcpy (save_time1, io_timeval);
9506 
9507  fileio_ctime (&backup_header_p->start_time, io_timeval);
9508  if (asprintf (&error_message_p,
9510  session_p->bkup.vlabel, save_time1, io_timeval) < 0)
9511  {
9513  return NULL;
9514  }
9515 
9516  if (fileio_make_error_message (thread_p, error_message_p) != NO_ERROR)
9517  {
9518  free (error_message_p);
9519  return NULL;
9520  }
9521 
9522  free (error_message_p);
9523  is_need_retry = true;
9524  goto retry_newvol;
9525  }
9526 
9527  /* Need to match the expected unit_num */
9528  if (unit_num != backup_header_p->unit_num)
9529  {
9530  if (asprintf (&error_message_p,
9532  session_p->bkup.vlabel, backup_header_p->unit_num, unit_num) < 0)
9533  {
9535  return NULL;
9536  }
9537 
9538  if (fileio_make_error_message (thread_p, error_message_p) != NO_ERROR)
9539  {
9540  free (error_message_p);
9541  return NULL;
9542  }
9543 
9544  free (error_message_p);
9545  is_need_retry = true;
9546  goto retry_newvol;
9547  }
9548 
9549  /* Should this one be treated as fatal? */
9550  expect_page_id = (is_first_time) ? FILEIO_BACKUP_START_PAGE_ID : FILEIO_BACKUP_VOL_CONT_PAGE_ID;
9551  if (backup_header_p->iopageid != expect_page_id)
9552  {
9553  if (asprintf (&error_message_p,
9555  session_p->bkup.vlabel) < 0)
9556  {
9558  return NULL;
9559  }
9560 
9561  if (fileio_make_error_message (thread_p, error_message_p) != NO_ERROR)
9562  {
9563  free (error_message_p);
9564  return NULL;
9565  }
9566  free (error_message_p);
9567  is_need_retry = true;
9568  goto retry_newvol;
9569  }
9570 
9571  /* NOTE: This could mess with restoring to a new location */
9572  if (strcmp (backup_header_p->db_fullname, db_full_name_p) != 0
9573  || (db_creation_time > 0 && difftime ((time_t) db_creation_time, (time_t) backup_header_p->db_creation)))
9574  {
9575  if (is_first_time)
9576  {
9577  char save_time1[64];
9578  char save_time2[64];
9579 
9580  fileio_ctime (&backup_header_p->db_creation, io_timeval);
9581  strcpy (save_time1, io_timeval);
9582 
9583  fileio_ctime (&db_creation_time, io_timeval);
9584  strcpy (save_time2, io_timeval);
9585 
9587  session_p->bkup.vlabel, backup_header_p->db_fullname, save_time1, db_full_name_p, save_time2);
9588  return NULL;
9589  }
9590  else
9591  {
9592  fileio_ctime (&backup_header_p->db_creation, io_timeval);
9593  if (asprintf (&error_message_p,
9595  session_p->bkup.vlabel, backup_header_p->db_fullname, io_timeval) < 0)
9596  {
9598  return NULL;
9599  }
9600 
9601  if (fileio_make_error_message (thread_p, error_message_p) != NO_ERROR)
9602  {
9603  free (error_message_p);
9604  return NULL;
9605  }
9606 
9607  free (error_message_p);
9608  is_need_retry = true;
9609  goto retry_newvol;
9610  }
9611  }
9612  }
9613  /* Passed all tests above */
9614  break;
9615  retry_newvol:
9616  is_original_header = false;
9617  /* close it, in case it was opened previously */
9618  if (session_p->bkup.vdes != NULL_VOLDES)
9619  {
9620  fileio_close (session_p->bkup.vdes);
9621  session_p->bkup.vdes = NULL_VOLDES;
9622  }
9623 
9624  /* Since there was a problem, let the user try again */
9625  if (fileio_find_restore_volume (thread_p, db_full_name_p, session_p->bkup.name, unit_num, level,
9627  {
9629  return NULL;
9630  }
9631  }
9632  while (is_need_retry);
9633  backup_header_p = session_p->bkup.bkuphdr;
9634  /*
9635  * If we read an archive header and notice that the buffer size
9636  * was different than our current bkup.iosize then we will have
9637  * to REALLOC the io areas set up in _init. Same for the
9638  * when the database IO pagesize changes.
9639  */
9640  if (backup_header_p->bkup_iosize > session_p->bkup.iosize)
9641  {
9642  session_p->bkup.buffer = (char *) realloc (session_p->bkup.buffer, backup_header_p->bkup_iosize);
9643  if (session_p->bkup.buffer == NULL)
9644  {
9645  return NULL;
9646  }
9647  session_p->bkup.ptr = session_p->bkup.buffer; /* reinit in case it moved */
9648  }
9649  /* Always use the saved size from the backup to restore with */
9650  session_p->bkup.iosize = backup_header_p->bkup_iosize;
9651  /* backuped page is bigger than the current DB pagesize. must resize read buffer */
9652  if (is_first_time)
9653  {
9654  if (backup_header_p->db_iopagesize > IO_PAGESIZE)
9655  {
9656  int io_pagesize, size;
9657  io_pagesize = backup_header_p->db_iopagesize;
9658  if (session_p->dbfile.level == FILEIO_BACKUP_FULL_LEVEL)
9659  {
9660  io_pagesize *= FILEIO_FULL_LEVEL_EXP;
9661  }
9662 
9664  free_and_init (session_p->dbfile.area);
9665  session_p->dbfile.area = (FILEIO_BACKUP_PAGE *) malloc (size);
9666  if (session_p->dbfile.area == NULL)
9667  {
9669  return NULL;
9670  }
9671  }
9672  }
9673 
9674  return session_p;
9675 }
9676 
9677 /*
9678  * fileio_finish_restore () - Finish the restore session
9679  * return:
9680  * session(in/out): The session array
9681  */
9682 int
9684 {
9685  int success;
9686 
9687  success = fileio_synchronize_all (thread_p, false);
9688  fileio_abort_restore (thread_p, session_p);
9689 
9690  return success;
9691 }
9692 
9693 /*
9694  * fileio_list_restore () - List description of current backup source
9695  * return: session or NULL
9696  * db_fullname(in): Name of the database to backup
9697  * backup_source(out): Name of backup source device (file or directory)
9698  * level(in): The presumed backup level
9699  * newvolpath(in): restore the database and log volumes to the path
9700  * specified in the database-loc-file
9701  */
9702 int
9703 fileio_list_restore (THREAD_ENTRY * thread_p, const char *db_full_name_p, char *backup_source_p,
9704  FILEIO_BACKUP_LEVEL level, bool is_new_vol_path)
9705 {
9706  FILEIO_BACKUP_SESSION backup_session;
9707  FILEIO_BACKUP_SESSION *session_p = &backup_session;
9708  FILEIO_BACKUP_HEADER *backup_header_p;
9709  FILEIO_BACKUP_FILE_HEADER *file_header_p;
9710  PGLENGTH db_iopagesize;
9711  float db_compatibility;
9712  int nbytes, i;
9713  INT64 db_creation_time = 0;
9714  char file_name[PATH_MAX];
9715  time_t tmp_time;
9716  char time_val[CTIME_MAX];
9717 
9718  if (fileio_start_restore (thread_p, db_full_name_p, backup_source_p, db_creation_time, &db_iopagesize,
9719  &db_compatibility, session_p, level, false, 0, NULL, is_new_vol_path) == NULL)
9720  {
9721  /* Cannot access backup file.. Restore from backup is cancelled */
9722  if (er_errid () == ER_GENERIC_ERROR)
9723  {
9725  }
9726  return ER_FAILED;
9727  }
9728 
9729  /* First backup header was just read */
9730  backup_header_p = session_p->bkup.bkuphdr;
9731  /* this check is probably redundant */
9732  if (backup_header_p->iopageid != FILEIO_BACKUP_START_PAGE_ID
9733  && backup_header_p->iopageid != FILEIO_BACKUP_VOL_CONT_PAGE_ID)
9734  {
9736  goto error;
9737  }
9738 
9739  /* Show the backup volume header information. */
9741 
9742  tmp_time = (time_t) backup_header_p->db_creation;
9743  (void) ctime_r (&tmp_time, time_val);
9745  backup_header_p->db_fullname, time_val, backup_header_p->db_iopagesize);
9747  backup_header_p->level, fileio_get_backup_level_string (backup_header_p->level),
9748  backup_header_p->start_lsa.pageid, backup_header_p->start_lsa.offset, backup_header_p->chkpt_lsa.pageid,
9749  backup_header_p->chkpt_lsa.offset);
9750 
9751  tmp_time = (time_t) backup_header_p->start_time;
9752  (void) ctime_r (&tmp_time, time_val);
9754  backup_header_p->unit_num);
9756  backup_header_p->db_release, backup_header_p->db_compatibility);
9758  backup_header_p->bkpagesize);
9760  backup_header_p->zip_method, fileio_get_zip_method_string (backup_header_p->zip_method),
9761  backup_header_p->zip_level, fileio_get_zip_level_string (backup_header_p->zip_level));
9763  backup_header_p->skip_activelog ? "NO" : "YES");
9764 
9765  for (i = FILEIO_BACKUP_FULL_LEVEL; i < FILEIO_BACKUP_UNDEFINED_LEVEL && backup_header_p->previnfo[i].at_time > 0; i++)
9766  {
9767  tmp_time = (time_t) backup_header_p->previnfo[i].at_time;
9768  (void) ctime_r (&tmp_time, time_val);
9770  time_val, backup_header_p->previnfo[i].lsa.pageid, backup_header_p->previnfo[i].lsa.offset);
9771  }
9772 
9773  if (strlen (backup_header_p->db_prec_bkvolname) > 0)
9774  {
9776  backup_header_p->db_prec_bkvolname);
9777  }
9778 
9779  /* Reminder this is not implemented yet, so no need to show it */
9780  if (strlen (backup_header_p->db_next_bkvolname) > 0)
9781  {
9783  backup_header_p->db_next_bkvolname);
9784  }
9785 
9786  fprintf (stdout, "\n");
9787  /* If this is not the first tape, then the header information of the backup is all we show. */
9788  if (backup_header_p->unit_num != FILEIO_INITIAL_BACKUP_UNITS)
9789  {
9790  return fileio_finish_restore (thread_p, session_p);
9791  }
9792 
9793  /* Start reading information of every database volumes/files of the database which is in backup. */
9794  file_header_p = (FILEIO_BACKUP_FILE_HEADER *) (&session_p->dbfile.area->iopage);
9795  while (true)
9796  {
9798  if (fileio_read_restore (thread_p, session_p, nbytes) != NO_ERROR)
9799  {
9801  goto error;
9802  }
9803 
9805  {
9806  break;
9807  }
9808 
9810  {
9812  goto error;
9813  }
9814 
9816  file_header_p->vlabel, file_header_p->volid, file_header_p->nbytes, CEIL_PTVDIV (file_header_p->nbytes,
9817  IO_PAGESIZE));
9818  session_p->dbfile.volid = file_header_p->volid;
9819  session_p->dbfile.nbytes = file_header_p->nbytes;
9820  strncpy (file_name, file_header_p->vlabel, PATH_MAX);
9821  session_p->dbfile.vlabel = file_name;
9822  /* Read all file pages until the end of the file */
9823  if (fileio_skip_restore_volume (thread_p, session_p) != NO_ERROR)
9824  {
9825  goto error;
9826  }
9827  }
9828 
9829  fprintf (stdout, "\n");
9830  return fileio_finish_restore (thread_p, session_p);
9831 error:
9832  fileio_abort_restore (thread_p, session_p);
9833  return ER_FAILED;
9834 }
9835 
9836 /*
9837  * fileio_get_backup_volume () - Get backup volume
9838  * return: session or NULL
9839  * db_fullname(in): Name of the database to backup
9840  * logpath(in): Directory where the log volumes reside
9841  * user_backuppath(in): Backup path that user specified
9842  * from_volbackup (out) : Name of the backup volume
9843  *
9844  */
9845 int
9846 fileio_get_backup_volume (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
9847  const char *user_backuppath, int try_level, char *from_volbackup)
9848 {
9849  FILE *backup_volinfo_fp = NULL; /* Pointer to backup */
9850  const char *nopath_name; /* Name without path */
9851  const char *volnameptr;
9852  int retry;
9853  int error_code = NO_ERROR;
9854  char format_string[64];
9855  struct stat stbuf;
9856 
9857  sprintf (format_string, "%%%ds", PATH_MAX - 1);
9858 
9859  nopath_name = fileio_get_base_file_name (db_fullname);
9860  fileio_make_backup_volume_info_name (from_volbackup, logpath, nopath_name);
9861 
9862  while ((stat (from_volbackup, &stbuf) == -1) || (backup_volinfo_fp = fopen (from_volbackup, "r")) == NULL)
9863  {
9864  /*
9865  * When user specifies an explicit location, the backup vinf
9866  * file is optional.
9867  */
9868  if (user_backuppath != NULL)
9869  {
9870  break;
9871  }
9872 
9873  /*
9874  * Backup volume information is not online
9875  */
9878  from_volbackup);
9880 
9881  if (scanf ("%d", &retry) != 1)
9882  {
9883  retry = 0;
9884  }
9885 
9886  switch (retry)
9887  {
9888  case 0: /* quit */
9889  /* Cannot access backup file.. Restore from backup is cancelled */
9890  error_code = ER_LOG_CANNOT_ACCESS_BACKUP;
9891  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, from_volbackup);
9892  return error_code;
9893 
9894  case 2:
9896  if (scanf (format_string, from_volbackup) != 1)
9897  {
9898  /* Cannot access backup file.. Restore from backup is cancelled */
9899  error_code = ER_LOG_CANNOT_ACCESS_BACKUP;
9900  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, from_volbackup);
9901  return error_code;
9902  }
9903  break;
9904 
9905  case 1:
9906  default:
9907  break;
9908  }
9909  }
9910 
9911  /*
9912  * If we get to here, we can read the bkvinf file, OR one does not
9913  * exist and it is not required.
9914  */
9915  if (backup_volinfo_fp != NULL)
9916  {
9918  {
9919  volnameptr =
9922  if (volnameptr != NULL)
9923  {
9924  strcpy (from_volbackup, volnameptr);
9925  }
9926  else
9927  {
9928  fileio_make_backup_name (from_volbackup, nopath_name, logpath, (FILEIO_BACKUP_LEVEL) try_level,
9930  }
9931  }
9932  else
9933  {
9934  fclose (backup_volinfo_fp);
9935  return ER_FAILED;
9936  }
9937 
9938  fclose (backup_volinfo_fp);
9939  }
9940 
9941  if (user_backuppath != NULL)
9942  {
9943  strncpy (from_volbackup, user_backuppath, PATH_MAX - 1);
9944  }
9945 
9946  return NO_ERROR;
9947 }
9948 
9949 
9950 /*
9951  * fileio_get_next_restore_file () - Find information of next file to restore
9952  * return: -1 A failure, 0 No more files to restore (End of BACKUP),
9953  * 1 There is a file to restore
9954  * session(in/out): The session array
9955  * filename(out): the name of next file to restore
9956  * volid(out): Identifier of the database volume/file to restore
9957  * vol_nbytes(out): Nbytes of the database volume/file to restore
9958  */
9959 int
9960 fileio_get_next_restore_file (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p, char *file_name_p,
9961  VOLID * vol_id_p)
9962 {
9963  FILEIO_BACKUP_FILE_HEADER *file_header_p;
9964  int nbytes;
9965  char file_path[PATH_MAX];
9966 
9967  /* Read the next database volume and/or file to restore. */
9968  file_header_p = (FILEIO_BACKUP_FILE_HEADER *) (&session_p->dbfile.area->iopage);
9970  if (fileio_read_restore (thread_p, session_p, nbytes) != NO_ERROR)
9971  {
9973  return -1;
9974  }
9975 
9977  {
9978  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DEVICE)
9979  {
9981  }
9982  return 0;
9983  }
9984 
9986  {
9987  return -1;
9988  }
9989 
9990  session_p->dbfile.volid = file_header_p->volid;
9991  session_p->dbfile.nbytes = file_header_p->nbytes;
9992  session_p->dbfile.level = session_p->bkup.bkuphdr->level;
9993 
9994  /* check for restoring the database and log volumes to the path specified in the database-loc-file */
9995  if (session_p->bkup.loc_db_fullname[0] != '\0')
9996  {
9997  /* replace filename with the databases.txt info */
9998  if ((session_p->dbfile.volid == LOG_DBLOG_BKUPINFO_VOLID) || (session_p->dbfile.volid == LOG_DBLOG_INFO_VOLID)
9999  || (session_p->dbfile.volid == LOG_DBLOG_ARCHIVE_VOLID)
10000  || (session_p->dbfile.volid == LOG_DBLOG_ACTIVE_VOLID))
10001  {
10002  sprintf (file_name_p, "%s%c%s", session_p->bkup.log_path, PATH_SEPARATOR,
10003  fileio_get_base_file_name (file_header_p->vlabel));
10004  }
10005  else
10006  {
10007  fileio_get_directory_path (file_path, session_p->bkup.loc_db_fullname);
10008  sprintf (file_name_p, "%s%c%s", file_path, PATH_SEPARATOR, fileio_get_base_file_name (file_header_p->vlabel));
10009  }
10010  }
10011  else
10012  {
10013  strncpy (file_name_p, file_header_p->vlabel, PATH_MAX);
10014  }
10015 
10016  *vol_id_p = session_p->dbfile.volid;
10017  return 1;
10018 }
10019 
10020 /*
10021  * fileio_fill_hole_during_restore () - Fill in a hole found in the backup during
10022  * a restore
10023  * return:
10024  * next_pageid(out):
10025  * stop_pageid(in):
10026  * session(in/out): The session array
10027  * page_bitmap(in): Page bitmap to record which pages have already
10028  * been restored
10029  *
10030  * Note: A hole is likely only for 2 reasons. After the system pages in
10031  * permament temp volumes, or at the end of a volume if we stop backing
10032  * up unallocated pages.
10033  */
10034 static int
10035 fileio_fill_hole_during_restore (THREAD_ENTRY * thread_p, int *next_page_id_p, int stop_page_id,
10037 {
10038  FILEIO_PAGE *malloc_io_pgptr = NULL;
10039 
10040  if (malloc_io_pgptr == NULL)
10041  {
10042  malloc_io_pgptr = (FILEIO_PAGE *) malloc (IO_PAGESIZE);
10043  if (malloc_io_pgptr == NULL)
10044  {
10046  return ER_FAILED;
10047  }
10048  memset ((char *) malloc_io_pgptr, 0, IO_PAGESIZE);
10049  (void) fileio_initialize_res (thread_p, malloc_io_pgptr, IO_PAGESIZE);
10050  }
10051 
10052  while (*next_page_id_p < stop_page_id)
10053  {
10054  /*
10055  * We did not back up a page since it was deallocated, or there
10056  * is a hole of some kind that must be filled in with correctly
10057  * formatted pages.
10058  */
10059  if (fileio_write_restore (thread_p, page_bitmap, session_p->dbfile.vdes, malloc_io_pgptr, session_p->dbfile.volid,
10060  *next_page_id_p, session_p->dbfile.level) == NULL)
10061  {
10063  return ER_FAILED;
10064  }
10065  *next_page_id_p += 1;
10066  }
10067 
10068  if (malloc_io_pgptr != NULL)
10069  {
10070  free_and_init (malloc_io_pgptr);
10071  }
10072 
10073  return NO_ERROR;
10074 }
10075 
10076 /*
10077  * fileio_decompress_restore_volume () - The number of bytes to decompress/read
10078  * from the backup destination
10079  * return:
10080  * session(in/out): The session array
10081  * nbytes(in): Number of bytes to read
10082  */
10083 static int
10085 {
10086  int error = NO_ERROR;
10087  FILEIO_THREAD_INFO *thread_info_p;
10088  FILEIO_QUEUE *queue_p;
10089  FILEIO_BACKUP_HEADER *backup_header_p;
10090  FILEIO_BACKUP_PAGE *save_area_p;
10091  FILEIO_NODE *node;
10092 
10093  assert (nbytes >= 0);
10094 
10095  thread_info_p = &session_p->read_thread_info;
10096  queue_p = &thread_info_p->io_queue;
10097  backup_header_p = session_p->bkup.bkuphdr;
10098  node = NULL;
10099 
10100  switch (backup_header_p->zip_method)
10101  {
10103  if (fileio_read_restore (thread_p, session_p, nbytes) != NO_ERROR)
10104  {
10105  error = ER_IO_RESTORE_READ_ERROR;
10106  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, backup_header_p->unit_num);
10107  goto exit_on_error;
10108  }
10109  break;
10110 
10111  case FILEIO_ZIP_LZ4_METHOD:
10112  {
10113  int rv;
10114  FILEIO_ZIP_PAGE *zip_page;
10115 
10116  /* alloc queue node */
10117  node = fileio_allocate_node (queue_p, backup_header_p);
10118  if (node == NULL)
10119  {
10120  goto exit_on_error;
10121  }
10122 
10123  assert (node->zip_info != NULL);
10124  zip_page = &node->zip_info->zip_page;
10125 
10126  save_area_p = session_p->dbfile.area; /* save link */
10127  session_p->dbfile.area = (FILEIO_BACKUP_PAGE *) zip_page;
10128 
10129  rv = fileio_read_restore (thread_p, session_p, sizeof (int));
10130  session_p->dbfile.area = save_area_p; /* restore link */
10131  if (rv != NO_ERROR)
10132  {
10133  error = ER_IO_RESTORE_READ_ERROR;
10134  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, backup_header_p->unit_num);
10135  goto exit_on_error;
10136  }
10137 
10138  /* sanity check of the size values */
10139  if (zip_page->buf_len > nbytes || zip_page->buf_len == 0)
10140  {
10141  error = ER_IO_LZ4_COMPRESS_FAIL; /* may be compress fail */
10142  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 4, backup_header_p->zip_method,
10143  fileio_get_zip_method_string (backup_header_p->zip_method), backup_header_p->zip_level,
10144  fileio_get_zip_level_string (backup_header_p->zip_level));
10145 #if defined(CUBRID_DEBUG)
10146  fprintf (stdout, "io_restore_volume_decompress_read: block size error - data corrupted\n");
10147 #endif /* CUBRID_DEBUG */
10148  goto exit_on_error;
10149  }
10150  else if (zip_page->buf_len < nbytes)
10151  {
10152  /* read compressed block data */
10153  int unzip_len;
10154 
10155  save_area_p = session_p->dbfile.area; /* save link */
10156  session_p->dbfile.area = (FILEIO_BACKUP_PAGE *) zip_page->buf;
10157 
10158  rv = fileio_read_restore (thread_p, session_p, zip_page->buf_len);
10159  session_p->dbfile.area = save_area_p; /* restore link */
10160  if (rv != NO_ERROR)
10161  {
10162  error = ER_IO_RESTORE_READ_ERROR;
10163  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, backup_header_p->unit_num);
10164  goto exit_on_error;
10165  }
10166 
10167  /* decompress - use safe decompressor as data might be corrupted during a file transfer */
10168  unzip_len =
10169  LZ4_decompress_safe ((const char *) zip_page->buf, (char *) session_p->dbfile.area, zip_page->buf_len,
10170  nbytes);
10171  if (unzip_len < 0 || unzip_len != nbytes)
10172  {
10173  error = ER_IO_LZ4_DECOMPRESS_FAIL;
10174  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
10175 #if defined(CUBRID_DEBUG)
10176  fprintf (stdout, "io_restore_volume_decompress_read: compressed data violation\n");
10177 #endif /* CUBRID_DEBUG */
10178  goto exit_on_error;
10179  }
10180  }
10181  else
10182  {
10183  /* no compressed block */
10184  rv = fileio_read_restore (thread_p, session_p, zip_page->buf_len);
10185  if (rv != NO_ERROR)
10186  {
10187  error = ER_IO_RESTORE_READ_ERROR;
10188  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, backup_header_p->unit_num);
10189  goto exit_on_error;
10190  }
10191  }
10192 
10193  }
10194  break;
10195 
10198  default:
10199  error = ER_IO_RESTORE_READ_ERROR;
10200  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, backup_header_p->unit_num);
10201  goto exit_on_error;
10202  }
10203 
10204 exit_on_end:
10205 
10206  /* free node */
10207  if (node)
10208  {
10209  (void) fileio_free_node (queue_p, node);
10210  }
10211 
10212  return error;
10213 exit_on_error:
10214 
10215  if (error == NO_ERROR)
10216  {
10217  error = ER_FAILED;
10218  }
10219  goto exit_on_end;
10220 }
10221 
10222 #if !defined(CS_MODE)
10223 /*
10224  * fileio_restore_volume () - Restore a volume/file of given database
10225  * return:
10226  * session_p(in/out): The session array
10227  * to_vlabel_p(in): Restore the next file using this name
10228  * verbose_to_vlabel_p(in): Printable volume name
10229  * prev_vlabel_p(out): Previous restored file name
10230  * page_bitmap(in): Page bitmap to record which pages have already
10231  * been restored
10232  * is_remember_pages(in): true if we need to track which pages are restored
10233  */
10234 int
10235 fileio_restore_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p, char *to_vol_label_p,
10236  char *verbose_to_vol_label_p, char *prev_vol_label_p, FILEIO_RESTORE_PAGE_BITMAP * page_bitmap,
10237  bool is_remember_pages)
10238 {
10239  int next_page_id = 0;
10240  INT64 total_nbytes = 0;
10241  int nbytes;
10242  int from_npages, npages;
10244  int check_ratio = 0, check_npages = 0;
10245  FILEIO_BACKUP_HEADER *backup_header_p = session_p->bkup.bkuphdr;
10246  int unit;
10247  int i;
10248  char *buffer_p;
10249  bool incremental_includes_volume_header = false;
10250 
10251  npages = (int) CEIL_PTVDIV (session_p->dbfile.nbytes, IO_PAGESIZE);
10252  session_p->dbfile.vlabel = to_vol_label_p;
10253  nbytes = (int) MIN (backup_header_p->bkpagesize, session_p->dbfile.nbytes);
10254  unit = nbytes / IO_PAGESIZE;
10255  if (nbytes % IO_PAGESIZE)
10256  {
10257  unit++;
10258  }
10259 
10260 #if defined(CUBRID_DEBUG)
10261  if (io_Bkuptrace_debug > 0)
10262  {
10264  session_p->dbfile.vlabel, session_p->dbfile.volid, session_p->dbfile.nbytes,
10265  CEIL_PTVDIV (session_p->dbfile.nbytes, IO_PAGESIZE));
10266  fprintf (stdout, "\n");
10267  }
10268 #endif /* CUBRID_DEBUG */
10269 
10270  if (session_p->verbose_fp)
10271  {
10272  fprintf (session_p->verbose_fp, " %-28s | %10d | ", fileio_get_base_file_name (verbose_to_vol_label_p), npages);
10273  check_ratio = 1;
10274  check_npages = (int) (((float) npages / 25.0) * check_ratio);
10275  }
10276 
10277  /*
10278  * Reformatting the volume guarantees no pollution from old contents.
10279  * Note that for incremental restores, one can only reformat the volume
10280  * once ... the first time that volume is replaced. This is needed
10281  * because we are applying the restoration in reverse time order.
10282  */
10283  if (!fileio_is_volume_exist (session_p->dbfile.vlabel))
10284  {
10285  session_p->dbfile.vdes =
10286  fileio_format (thread_p, NULL, session_p->dbfile.vlabel, session_p->dbfile.volid, npages, false, false, false,
10287  IO_PAGESIZE, 0, false);
10288  }
10289  else
10290  {
10291  session_p->dbfile.vdes =
10292  fileio_mount (thread_p, NULL, session_p->dbfile.vlabel, session_p->dbfile.volid, false, false);
10293  }
10294 
10295  if (session_p->dbfile.vdes == NULL_VOLDES)
10296  {
10297  goto error;
10298  }
10299 
10300  /* For some volumes we do not keep track of the individual pages restored. */
10301  bitmap = (is_remember_pages) ? page_bitmap : NULL;
10302  /* Read all file pages until the end of the volume/file. */
10303  from_npages = (int) CEIL_PTVDIV (session_p->dbfile.nbytes, backup_header_p->bkpagesize);
10304  nbytes = FILEIO_RESTORE_DBVOLS_IO_PAGE_SIZE (session_p);
10305 
10306  while (true)
10307  {
10308  if (fileio_decompress_restore_volume (thread_p, session_p, nbytes) != NO_ERROR)
10309  {
10310  goto error;
10311  }
10312 
10314  {
10315  /*
10316  * End of File marker in backup, but may not be true end of file being
10317  * restored so we have to continue filling in pages until the
10318  * restored volume is finished.
10319  */
10320  if (session_p->dbfile.level == FILEIO_BACKUP_FULL_LEVEL && next_page_id < npages)
10321  {
10322  if (fileio_fill_hole_during_restore (thread_p, &next_page_id, npages, session_p, bitmap) != NO_ERROR)
10323  {
10324  goto error;
10325  }
10326  }
10327  break;
10328  }
10329 
10330  if (FILEIO_GET_BACKUP_PAGE_ID (session_p->dbfile.area) > from_npages)
10331  {
10332  /* Too many pages for this volume according to the file header */
10334  FILEIO_GET_BACKUP_PAGE_ID (session_p->dbfile.area), from_npages, session_p->dbfile.volid);
10335  goto error;
10336  }
10337 
10338 #if defined(CUBRID_DEBUG)
10339  fprintf (stdout, "fileio_restore_volume: %d\t%d,\t%d\n",
10340  ((FILEIO_BACKUP_PAGE *) (session_p->dbfile.area))->iopageid,
10341  *(PAGEID *) (((char *) (session_p->dbfile.area)) + offsetof (FILEIO_BACKUP_PAGE, iopage) +
10342  backup_header_p->bkpagesize), backup_header_p->bkpagesize);
10343 #endif
10344 
10345  if (!FILEIO_CHECK_RESTORE_PAGE_ID (session_p->dbfile.area, backup_header_p->bkpagesize))
10346  {
10348  goto error;
10349  }
10350 
10351  /* Check for holes and fill them (only for full backup level) */
10352  if (session_p->dbfile.level == FILEIO_BACKUP_FULL_LEVEL
10353  && (next_page_id < FILEIO_GET_BACKUP_PAGE_ID (session_p->dbfile.area)))
10354  {
10355  if (fileio_fill_hole_during_restore (thread_p, &next_page_id, session_p->dbfile.area->iopageid, session_p,
10356  bitmap) != NO_ERROR)
10357  {
10358  goto error;
10359  }
10360  }
10361 
10362  /* Restore the page we just read in */
10363  if (session_p->dbfile.level != FILEIO_BACKUP_FULL_LEVEL)
10364  {
10365  next_page_id = FILEIO_GET_BACKUP_PAGE_ID (session_p->dbfile.area);
10366  if (next_page_id == DISK_VOLHEADER_PAGE)
10367  {
10368  incremental_includes_volume_header = true;
10369  }
10370  }
10371 
10372  buffer_p = (char *) &session_p->dbfile.area->iopage;
10373  for (i = 0; i < unit && next_page_id < npages; i++)
10374  {
10375  if (fileio_write_restore (thread_p, bitmap, session_p->dbfile.vdes, buffer_p + i * IO_PAGESIZE,
10376  session_p->dbfile.volid, next_page_id, session_p->dbfile.level) == NULL)
10377  {
10379  goto error;
10380  }
10381 
10382  next_page_id += 1;
10383  total_nbytes += IO_PAGESIZE;
10384  if (session_p->verbose_fp && npages >= 25 && next_page_id >= check_npages)
10385  {
10386  fprintf (session_p->verbose_fp, "#");
10387  check_ratio++;
10388  check_npages = (int) (((float) npages / 25.0) * check_ratio);
10389  }
10390  }
10391  }
10392 
10393  if (total_nbytes > session_p->dbfile.nbytes && session_p->dbfile.volid < LOG_DBFIRST_VOLID)
10394  {
10395  (void) ftruncate (session_p->dbfile.vdes, session_p->dbfile.nbytes);
10396  }
10397 
10398 #if defined(CUBRID_DEBUG)
10399  if (io_Bkuptrace_debug >= 2 && bitmap)
10400  {
10401  fileio_page_bitmap_dump (stdout, bitmap);
10402  (void) fprintf (stdout, "\n\n");
10403  }
10404 #endif /* CUBRID_DEBUG */
10405 
10406  /* check for restoring the database and log volumes to the path specified in the database-loc-file */
10407  if (session_p->bkup.loc_db_fullname[0] != '\0' && session_p->dbfile.volid >= LOG_DBFIRST_VOLID)
10408  {
10409  /* Volume header page may not be included in incremental backup volumes.
10410  * This means that volume header of a partially restoredb volume may not exist.
10411  */
10412  if (session_p->dbfile.level == FILEIO_BACKUP_FULL_LEVEL || incremental_includes_volume_header == true)
10413  {
10414  VOLID volid;
10415 
10416  volid = session_p->dbfile.volid;
10417  if (disk_set_creation (thread_p, volid, to_vol_label_p, &backup_header_p->db_creation,
10418  &session_p->bkup.last_chkpt_lsa, false, DISK_FLUSH_AND_INVALIDATE) != NO_ERROR)
10419  {
10420  goto error;
10421  }
10422 
10423  if (volid != LOG_DBFIRST_VOLID)
10424  {
10425  VOLID prev_volid;
10426  int prev_vdes;
10427 
10428  /* previous vol */
10429  prev_volid = fileio_find_previous_perm_volume (thread_p, volid);
10430  prev_vdes = fileio_mount (thread_p, NULL, prev_vol_label_p, prev_volid, false, false);
10431  if (prev_vdes == NULL_VOLDES)
10432  {
10433  goto error;
10434  }
10435 
10436  if (disk_set_link (thread_p, prev_volid, volid, to_vol_label_p, false, DISK_FLUSH_AND_INVALIDATE) !=
10437  NO_ERROR)
10438  {
10439  fileio_dismount (thread_p, prev_vdes);
10440  goto error;
10441  }
10442 
10443  fileio_dismount (thread_p, prev_vdes);
10444  }
10445  }
10446 
10447  /* save current volname */
10448  strncpy (prev_vol_label_p, to_vol_label_p, PATH_MAX);
10449  }
10450 
10451  fileio_dismount (thread_p, session_p->dbfile.vdes);
10452  session_p->dbfile.vdes = NULL_VOLDES;
10453  session_p->dbfile.volid = NULL_VOLID;
10454  session_p->dbfile.vlabel = NULL;
10455 
10456  if (session_p->verbose_fp)
10457  {
10458  if (next_page_id < 25)
10459  {
10460  fprintf (session_p->verbose_fp, "######################### | done\n");
10461  }
10462  else
10463  {
10464  while (check_ratio <= 25)
10465  {
10466  fprintf (session_p->verbose_fp, "#");
10467  check_ratio++;
10468  }
10469  fprintf (session_p->verbose_fp, " | done\n");
10470  }
10471  }
10472 
10473  return NO_ERROR;
10474 
10475 error:
10476  if (session_p->dbfile.vdes != NULL_VOLDES)
10477  {
10478  fileio_dismount (thread_p, session_p->dbfile.vdes);
10479  }
10480 
10481  session_p->dbfile.vdes = NULL_VOLDES;
10482  session_p->dbfile.volid = NULL_VOLID;
10483  session_p->dbfile.vlabel = NULL;
10484 
10485  return ER_FAILED;
10486 }
10487 #endif /* !CS_MODE */
10488 
10489 /*
10490  * fileio_write_restore () - Write the content of the page described by pageid
10491  * to disk
10492  * return: o_pgptr on success, NULL on failure
10493  * page_bitmap(in): Page bitmap to record which pages have already
10494  * been restored
10495  * vdes(in): Volume descriptor
10496  * io_pgptr(in): In-memory address where the current content of page resides
10497  * vol_id(in): volume identifier
10498  * page_id(in): Page identifier
10499  * level(in): backup level page restored from
10500  *
10501  * Note: The contents of the page stored on io_pgptr buffer which is
10502  * IO_PAGESIZE long are sent to disk using fileio_write. The restore pageid
10503  * cache is updated.
10504  */
10505 static void *
10506 fileio_write_restore (THREAD_ENTRY * thread_p, FILEIO_RESTORE_PAGE_BITMAP * page_bitmap, int vol_fd, void *io_page_p,
10507  VOLID vol_id, PAGEID page_id, FILEIO_BACKUP_LEVEL level)
10508 {
10509  bool is_set;
10511 
10512 #if !defined (CS_MODE)
10514 #endif
10515 
10516  if (page_bitmap == NULL)
10517  {
10518  /* don't care about ht for this volume */
10519  if (fileio_write (thread_p, vol_fd, io_page_p, page_id, IO_PAGESIZE, write_mode) == NULL)
10520  {
10521  return NULL;
10522  }
10523  }
10524  else
10525  {
10526 #if !defined(NDEBUG)
10527  assert (page_bitmap->vol_id == vol_id);
10528 #endif
10529  is_set = fileio_page_bitmap_is_set (page_bitmap, page_id);
10530 
10531  if (!is_set)
10532  {
10533  if (fileio_write (thread_p, vol_fd, io_page_p, page_id, IO_PAGESIZE, write_mode) == NULL)
10534  {
10535  return NULL;
10536  }
10537 
10538  if (level > FILEIO_BACKUP_FULL_LEVEL)
10539  {
10540  fileio_page_bitmap_set (page_bitmap, page_id);
10541  }
10542  }
10543  }
10544 
10545  return io_page_p;
10546 }
10547 
10548 /*
10549  * fileio_skip_restore_volume () - Skip over the next db volume from the backup
10550  * during a restore
10551  * return:
10552  * session(in/out): The session array
10553  *
10554  * Note: Basically have to read all of the pages until we get to the end of
10555  * the current backup file. It is necessary to "fast forward" to the
10556  * next backup meta-data.
10557  */
10558 int
10560 {
10561  int nbytes;
10562  FILEIO_BACKUP_HEADER *backup_header_p = session_p->bkup.bkuphdr;
10563 
10564  /* Read all file pages until the end of the volume/file. */
10565  nbytes = FILEIO_RESTORE_DBVOLS_IO_PAGE_SIZE (session_p);
10566  while (true)
10567  {
10568  if (fileio_decompress_restore_volume (thread_p, session_p, nbytes) != NO_ERROR)
10569  {
10570  goto error;
10571  }
10572 
10574  {
10575  /* End of FILE */
10576  break;
10577  }
10578 
10579 #if defined(CUBRID_DEBUG)
10580  fprintf (stdout, "fileio_skip_restore_volume: %d\t%d,\t%d\n",
10581  ((FILEIO_BACKUP_PAGE *) (session_p->dbfile.area))->iopageid,
10582  *(PAGEID *) (((char *) (session_p->dbfile.area)) + offsetof (FILEIO_BACKUP_PAGE, iopage) +
10583  backup_header_p->bkpagesize), backup_header_p->bkpagesize);
10584 #endif
10585 
10586  if (!FILEIO_CHECK_RESTORE_PAGE_ID (session_p->dbfile.area, backup_header_p->bkpagesize))
10587  {
10589  goto error;
10590  }
10591  }
10592 
10593  session_p->dbfile.vdes = NULL_VOLDES;
10594  session_p->dbfile.volid = NULL_VOLID;
10595  session_p->dbfile.vlabel = NULL;
10596 
10597  return NO_ERROR;
10598 
10599 error:
10600 
10601  session_p->dbfile.vdes = NULL_VOLDES;
10602  session_p->dbfile.volid = NULL_VOLID;
10603  session_p->dbfile.vlabel = NULL;
10604 
10605  return ER_FAILED;
10606 }
10607 
10608 /*
10609  * fileio_find_restore_volume () - FIND NEW LOCATION OF A VOLUME TO RESTORE
10610  * return:
10611  * dbname(in): The name of the database to which the volume belongs
10612  * to_volname(in): Name we think the volume is supposed to be
10613  * unit_num(in):
10614  * level(in): the backup level needed for restoration
10615  * reason(in):
10616  *
10617  * Note: Prompt the user to tell us the path to backup volume we cannot seem
10618  * to find. Note that validation is not done here it must be done by
10619  * the caller.
10620  */
10622 fileio_find_restore_volume (THREAD_ENTRY * thread_p, const char *db_name_p, char *to_vol_name_p, int unit_num,
10623  FILEIO_BACKUP_LEVEL level, int reason)
10624 {
10625  char *ptr1 = NULL, *ptr2 = NULL, *ptr3 = NULL, *ptr4 = NULL;
10626  char new_vol_name[FILEIO_MAX_USER_RESPONSE_SIZE];
10627  char *fail_prompt_p = NULL;
10628  char *reprompt_p = NULL;
10629  char *full_message_p = NULL;
10631 
10632  /* Try to build up the outgoing message */
10634  || asprintf (&ptr2, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_IO, reason)) < 0
10636  db_name_p, to_vol_name_p, unit_num, level, fileio_get_backup_level_string (level)) < 0
10639  {
10641  rval = FILEIO_RELOCATION_QUIT;
10642  goto end;
10643  }
10644 
10648  || asprintf (&full_message_p, "%s%s%s%s%s", ptr1, ptr2, ptr3, ptr4, ptr1) < 0)
10649  {
10651  rval = FILEIO_RELOCATION_QUIT;
10652  goto end;
10653  }
10654 
10656  new_vol_name, fail_prompt_p, FILEIO_RELOCATION_QUIT, FILEIO_RELOCATION_ALTERNATE,
10657  reprompt_p, FILEIO_RELOCATION_ALTERNATE) != NO_ERROR)
10658  {
10659  rval = FILEIO_RELOCATION_QUIT;
10660  goto end;
10661  }
10662 
10663  /* interpret the user responses. */
10664  if (new_vol_name[0] - '0' == FILEIO_RELOCATION_RETRY)
10665  {
10666  rval = FILEIO_RELOCATION_RETRY;
10667  }
10668  else if (new_vol_name[0] - '0' == FILEIO_RELOCATION_ALTERNATE)
10669  {
10671  strcpy (to_vol_name_p, &new_vol_name[1]);
10672  }
10673  else
10674  {
10675  rval = FILEIO_RELOCATION_QUIT;
10676  }
10677 
10678 end:
10679  if (ptr1)
10680  {
10681  free (ptr1);
10682  }
10683 
10684  if (ptr2)
10685  {
10686  free (ptr2);
10687  }
10688 
10689  if (ptr3)
10690  {
10691  free (ptr3);
10692  }
10693 
10694  if (ptr4)
10695  {
10696  free (ptr4);
10697  }
10698 
10699  if (fail_prompt_p)
10700  {
10701  free (fail_prompt_p);
10702  }
10703 
10704  if (reprompt_p)
10705  {
10706  free (reprompt_p);
10707  }
10708 
10709  if (full_message_p)
10710  {
10711  free (full_message_p);
10712  }
10713 
10714  return rval;
10715 }
10716 
10717 /*
10718  * fileio_get_backup_level_string () - return the string name of the backup level
10719  * return: pointer to string containing name of level
10720  * level(in): the backup level to convert
10721  */
10722 static const char *
10724 {
10725  switch (level)
10726  {
10728  return ("FULL LEVEL");
10729 
10731  return ("INCREMENTAL LEVEL 1");
10732 
10734  return ("INCREMENTAL LEVEL 2");
10735 
10736  default:
10737  return ("UNKNOWN");
10738  }
10739 }
10740 
10741 /*
10742  * fileio_get_zip_method_string () - return the string name of the compression method
10743  * return: pointer to string containing name of zip_method
10744  * zip_method(in): the compression method to convert
10745  */
10746 const char *
10748 {
10749  switch (zip_method)
10750  {
10752  return ("NONE");
10753 
10755  return ("LZO1X");
10756 
10757  case FILEIO_ZIP_LZ4_METHOD:
10758  return ("LZ4");
10759 
10761  return ("ZLIB");
10762 
10763  default:
10764  return ("UNKNOWN");
10765  }
10766 }
10767 
10768 /*
10769  * fileio_get_zip_level_string () - return the string name of the compression level
10770  * return: pointer to string containing name of zip_level
10771  * zip_level(in): the compression level to convert
10772  */
10773 const char *
10775 {
10776  switch (zip_level)
10777  {
10778  case FILEIO_ZIP_NONE_LEVEL:
10779  return ("NONE");
10780 
10781  case FILEIO_ZIP_1_LEVEL:
10782  return ("ZIP LEVEL 1");
10783 
10784  default:
10785  return ("UNKNOWN");
10786  }
10787 }
10788 
10789 /*
10790  * fileio_get_next_backup_volume () - FIND LOCATION OR NEW VOLUME NAME TO CONTINUE BACKUP
10791  * return:
10792  * session(in/out): The session array
10793  * user_new(in): true if user must be involved in the switch
10794  *
10795  * Note: This routine halts output to the current backup volume and opens the
10796  * next backup volume, creating it if it is a file. User interaction may
10797  * be necessary in cases where the backup volume is really a device
10798  * (i.e. because a tape must be mounted). User interaction may also be
10799  * required if the disk space is full on the current disk. We must
10800  * insure that new location chosen is large enough.
10801  */
10802 static int
10803 fileio_get_next_backup_volume (THREAD_ENTRY * thread_p, FILEIO_BACKUP_SESSION * session_p, bool is_new_user)
10804 {
10805  const char *db_nopath_name_p = NULL;
10806  char copy_name[PATH_MAX];
10807  char orig_name[PATH_MAX];
10808  char *message_area_p = NULL;
10809  char io_timeval[CTIME_MAX];
10810 
10811  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DIRECTORY)
10812  {
10813  fileio_dismount (thread_p, session_p->bkup.vdes);
10814  }
10815  else
10816  {
10817  fileio_dismount_without_fsync (thread_p, session_p->bkup.vdes);
10818  }
10819  session_p->bkup.vdes = NULL_VOLDES;
10820  /* Always force a new one for devices */
10821  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DEVICE)
10822  {
10823  is_new_user = true;
10824  }
10825 
10826  /* Keep the backup info correct */
10827  session_p->bkup.alltotalio += session_p->bkup.voltotalio;
10828  session_p->bkup.voltotalio = 0;
10829  /* Tell user that current backup volume just completed */
10830  fileio_ctime (&session_p->bkup.bkuphdr->start_time, io_timeval);
10832  session_p->bkup.bkuphdr->level, session_p->bkup.bkuphdr->unit_num,
10833  fileio_get_base_file_name (session_p->bkup.bkuphdr->db_fullname), io_timeval) < 0)
10834  {
10835  /* Note: we do not know the exact malloc size that failed */
10837  return ER_FAILED;
10838  }
10839  else
10840  {
10841  (void) fileio_request_user_response (thread_p, FILEIO_PROMPT_DISPLAY_ONLY, message_area_p, NULL, NULL, -1, -1,
10842  NULL, -1);
10843  /* Note: Not free_and_init */
10844  free (message_area_p);
10845  }
10846 
10847  /* Some initializations for start of next backup volume. */
10849  session_p->bkup.bkuphdr->unit_num++;
10850  memset (session_p->bkup.bkuphdr->db_prec_bkvolname, 0, sizeof (session_p->bkup.bkuphdr->db_prec_bkvolname));
10851  strcpy (session_p->bkup.bkuphdr->db_prec_bkvolname, session_p->bkup.vlabel);
10852  memset (session_p->bkup.bkuphdr->db_next_bkvolname, 0, sizeof (session_p->bkup.bkuphdr->db_next_bkvolname));
10853 
10854  /* Guess new path name in same dir as current volume. For devices, just repeat the device name. */
10855  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DIRECTORY)
10856  {
10857  /* First, get the path of the just finished volume. */
10858  fileio_get_directory_path (orig_name, session_p->bkup.name);
10859  strcpy (copy_name, orig_name);
10860  if (is_new_user)
10861  {
10862  /* Fill in the expected volume name to show the user */
10863  db_nopath_name_p = fileio_get_base_file_name (session_p->bkup.bkuphdr->db_fullname);
10864  fileio_make_backup_name (session_p->bkup.name, db_nopath_name_p, orig_name, session_p->bkup.bkuphdr->level,
10865  session_p->bkup.bkuphdr->unit_num + 1);
10866  strcpy (copy_name, session_p->bkup.name);
10867  }
10868  }
10869  else
10870  {
10871  strcpy (copy_name, session_p->bkup.name);
10872  strcpy (orig_name, session_p->bkup.name);
10873  }
10874 
10875  do
10876  {
10877  if (is_new_user)
10878  {
10879  if (fileio_find_restore_volume (thread_p, session_p->bkup.bkuphdr->db_fullname, copy_name,
10880  session_p->bkup.bkuphdr->unit_num, session_p->dbfile.level,
10882  {
10884  return ER_FAILED;
10885  }
10886  }
10887 
10888  /* Append backup volume name onto directory. */
10889  if (session_p->bkup.dtype == FILEIO_BACKUP_VOL_DIRECTORY)
10890  {
10891  db_nopath_name_p = fileio_get_base_file_name (session_p->bkup.bkuphdr->db_fullname);
10892  fileio_make_backup_name (session_p->bkup.name, db_nopath_name_p, copy_name, session_p->dbfile.level,
10893  session_p->bkup.bkuphdr->unit_num);
10894  }
10895  else
10896  {
10897  strcpy (session_p->bkup.name, copy_name);
10898  }
10899 
10900 
10901  session_p->bkup.vlabel = session_p->bkup.name;
10902  /* Create the new volume and go on with our lives */
10903  session_p->bkup.vdes =
10904  fileio_create_backup_volume (thread_p, session_p->bkup.bkuphdr->db_fullname, session_p->bkup.vlabel,
10905  LOG_DBCOPY_VOLID, false, false,
10906  ((session_p->dbfile.level == FILEIO_BACKUP_FULL_LEVEL)
10908  if (session_p->bkup.vdes < 0)
10909  {
10910 
10912  if (asprintf (&message_area_p, "%s\n", er_msg ()) < 0)
10913  {
10914  fileio_request_user_response (thread_p, FILEIO_PROMPT_DISPLAY_ONLY, message_area_p, NULL, NULL, -1, -1,
10915  NULL, -1);
10916  free (message_area_p);
10917  }
10918  }
10919 
10920  is_new_user = true;
10921  /* reset to the original name until acceptable alternative is chosen */
10922  strcpy (copy_name, orig_name);
10923  }
10924  while (session_p->bkup.vdes == NULL_VOLDES);
10925 
10926  /* Remember name of new backup volume */
10927  if (fileio_add_volume_to_backup_info (session_p->bkup.name, session_p->dbfile.level,
10929  {
10930  return ER_FAILED;
10931  }
10932 
10933  return NO_ERROR;
10934 }
10935 
10936 
10937 /*
10938  * BKVINF RELATED FUNCTIONS
10939  *
10940  * These functions collectively manage the bkvinf file. They are responsible
10941  * for reading, writing, and maintaining the in memory cache of backup
10942  * volume related information.
10943  */
10944 
10945 /*
10946  * fileio_add_volume_to_backup_info () - Add a backup volume name to the internal cache
10947  * return:
10948  * name(in): Filename of backup volume
10949  * level(in): backup level for that volume
10950  * unit_num(in): unit (or sequence) number of that volume
10951  * which_bkvinf(in):
10952  */
10953 int
10954 fileio_add_volume_to_backup_info (const char *name_p, FILEIO_BACKUP_LEVEL level, int unit_num, int which_bkvinf)
10955 {
10956  FILEIO_BACKUP_INFO_ENTRY *node_p, *back_p;
10957  struct stat stbuf;
10958  char real_path_buf[PATH_MAX];
10959  FILEIO_BACKUP_INFO_QUEUE *data_p;
10960 
10961  data_p = &(fileio_Backup_vol_info_data[which_bkvinf]);
10962  if ((!(*data_p).initialized) && fileio_initialize_backup_info (which_bkvinf) != NO_ERROR)
10963  {
10964  return ER_FAILED;
10965  }
10966 
10967  /* Get a node */
10968  node_p = fileio_allocate_backup_info (which_bkvinf);
10969  if (node_p == NULL)
10970  {
10971  return ER_FAILED;
10972  }
10973 
10974  if (stat (name_p, &stbuf) != -1)
10975  {
10976  if (S_ISREG (stbuf.st_mode))
10977  {
10978  /* for regular file, convert to the real-path */
10979  if (realpath (name_p, real_path_buf) != NULL)
10980  {
10981  name_p = real_path_buf;
10982  }
10983  }
10984  }
10985 
10986  strncpy (node_p->bkvol_name, name_p, PATH_MAX - 1);
10987  node_p->unit_num = unit_num;
10988 
10989  /* Put it on the queue for that level */
10990  if ((*data_p).anchors[level] == NULL)
10991  {
10992  /* this is the first one */
10993  (*data_p).anchors[level] = node_p;
10994  }
10995  else
10996  {
10997  /* Put it at the end of the chain */
10998  back_p = (*data_p).anchors[level];
10999  while (back_p->link != NULL)
11000  {
11001  if (back_p->unit_num == unit_num)
11002  {
11003  er_log_debug (ARG_FILE_LINE, "bkvinf inconsistency, duplicate unit num %d found for level %d\n",
11004  unit_num, level);
11005  }
11006  back_p = back_p->link;
11007  }
11008  /* check the last entry */
11009  if (back_p->unit_num == unit_num)
11010  {
11011  er_log_debug (ARG_FILE_LINE, "bkvinf inconsistency, duplicate unit num %d found for level %d\n", unit_num,
11012  level);
11013  }
11014 
11015  back_p->link = node_p;
11016  }
11017 
11018  return NO_ERROR;
11019 }
11020 
11021 /*
11022  * fileio_write_backup_info_entries () - Prints internal bkvinf table in a format
11023  * suitable for the bkvinf file as well as human
11024  * consumption
11025  * return:
11026  * fp(in): Open file handle or else NULL for stdout
11027  * which_bkvinf(in):
11028  */
11029 int
11030 fileio_write_backup_info_entries (FILE * fp, int which_bkvinf)
11031 {
11032  FILEIO_BACKUP_INFO_ENTRY *node_p;
11033  int level, n;
11034  FILEIO_BACKUP_INFO_QUEUE *data_p;
11035 
11036  data_p = &(fileio_Backup_vol_info_data[which_bkvinf]);
11037  if (!fp)
11038  {
11039  fp = stdout;
11040  }
11041 
11042  for (level = FILEIO_BACKUP_FULL_LEVEL; level < FILEIO_BACKUP_UNDEFINED_LEVEL; level++)
11043  {
11044  for (node_p = (*data_p).anchors[level]; node_p != NULL; node_p = node_p->link)
11045  {
11046  n = fprintf (fp, "%3d %d %s\n", level, node_p->unit_num, node_p->bkvol_name);
11047  if (n <= 0)
11048  {
11049  return ER_FAILED;
11050  }
11051  }
11052  }
11053 
11054  return NO_ERROR;
11055 }
11056 
11057 /*
11058  * fileio_read_backup_info_entries () - Read and parse the entries in a bkvinf file and
11059  * store them in the internal cache
11060  * return:
11061  * fp(in): Open file handle
11062  * which_bkvinf(in):
11063  */
11064 int
11065 fileio_read_backup_info_entries (FILE * fp, int which_bkvinf)
11066 {
11067  FILEIO_BACKUP_LEVEL level;
11068  int tmp, unit_num;
11069  char vol_name[PATH_MAX];
11070  int n, line = 0;
11071  char format_string[32];
11072 
11073  if (fp == NULL)
11074  {
11075  return ER_FAILED;
11076  }
11077 
11078  /* Always throw away old cache (if any) and then start fresh */
11079  fileio_finalize_backup_info (which_bkvinf);
11080  if (fileio_initialize_backup_info (which_bkvinf) != NO_ERROR)
11081  {
11082  return ER_FAILED;
11083  }
11084 
11085  sprintf (format_string, "%%d %%d %%%ds", PATH_MAX - 1);
11086  while ((n = fscanf (fp, format_string, &tmp, &unit_num, vol_name)) > 0)
11087  {
11088  level = (FILEIO_BACKUP_LEVEL) tmp;
11089  line++;
11090  if ((n != 3) || (level >= FILEIO_BACKUP_UNDEFINED_LEVEL)
11091  /* || (level < FILEIO_BACKUP_FULL_LEVEL) */
11092  || (unit_num < FILEIO_INITIAL_BACKUP_UNITS))
11093  {
11095  line);
11096  return ER_FAILED;
11097  }
11098 
11099  /* remember this backup volume */
11100  if (fileio_add_volume_to_backup_info (vol_name, level, unit_num, which_bkvinf) != NO_ERROR)
11101  {
11102  return ER_FAILED;
11103  }
11104  }
11105 
11106  return NO_ERROR;
11107 }
11108 
11109 
11110 /*
11111  * fileio_get_backup_info_volume_name () - Return the string of volume name
11112  * return:
11113  * level(in):
11114  * unit_num(in):
11115  * which_bkvinf(in):
11116  */
11117 const char *
11118 fileio_get_backup_info_volume_name (FILEIO_BACKUP_LEVEL level, int unit_num, int which_bkvinf)
11119 {
11120  FILEIO_BACKUP_INFO_ENTRY *node_p;
11121  FILEIO_BACKUP_INFO_QUEUE *data_p;
11122 
11123  data_p = &(fileio_Backup_vol_info_data[which_bkvinf]);
11124  for (node_p = (*data_p).anchors[level]; node_p != NULL; node_p = node_p->link)
11125  {
11126  if (unit_num == node_p->unit_num)
11127  {
11128  return (node_p->bkvol_name);
11129  }
11130  }
11131 
11132  return NULL;
11133 }
11134 
11135 
11136 /*
11137  * fileio_finalize_backup_info () - Clean up and free all resources related to the bkvinf
11138  * cache
11139  * return: void
11140  * which_bkvinf(in):
11141  */
11142 void
11144 {
11145  FILEIO_BACKUP_INFO_QUEUE *data_p;
11146 
11147  data_p = &(fileio_Backup_vol_info_data[which_bkvinf]);
11148  if ((*data_p).initialized)
11149  {
11151  (*data_p).initialized = false;
11152  }
11153  return;
11154 }
11155 
11156 /*
11157  * fileio_initialize_backup_info () - Initialize the bkvinf cache and related structures
11158  * return:
11159  * which_bkvinf(in):
11160  *
11161  * Note: Be sure to call bkvinf_final when the backups are complete.
11162  */
11163 static int
11165 {
11166  FILEIO_BACKUP_INFO_QUEUE *data_p;
11167 
11168 #if defined(CUBRID_DEBUG)
11169  const char *env_value;
11170  /* This checking is done here so it can be in one location and because this routine is likely to be called before
11171  * backup/restore. */
11172  if (io_Bkuptrace_debug < 0)
11173  {
11174  /* Find out if user wants debugging info during backup/restore. */
11175  env_value = envvar_get ("IO_TRACE_BACKUP");
11176  io_Bkuptrace_debug = (env_value == NULL ? 0 : atoi (env_value));
11177  }
11178 #endif /* CUBRID_DEBUG */
11179 
11180  data_p = &(fileio_Backup_vol_info_data[which_bkvinf]);
11181  if (!(*data_p).initialized)
11182  {
11183  (*data_p).free = NULL;
11184  memset ((*data_p).anchors, 0, sizeof ((*data_p).anchors));
11185  (*data_p).initialized = true;
11186  }
11187 
11188  return NO_ERROR;
11189 }
11190 
11191 /*
11192  * fileio_allocate_backup_info () - Allocate a bkvinf_entry
11193  * return: a pointer to the node allocated, or NULL if failure
11194  * which_bkvinf(in):
11195  */
11196 static FILEIO_BACKUP_INFO_ENTRY *
11198 {
11199  FILEIO_BACKUP_INFO_ENTRY *temp_entry_p;
11200  FILEIO_BACKUP_INFO_QUEUE *data_p;
11201 
11202  data_p = &(fileio_Backup_vol_info_data[which_bkvinf]);
11203  if (!(*data_p).initialized)
11204  {
11205  return NULL;
11206  }
11207 
11208  /* check free list */
11209  if ((*data_p).free != NULL)
11210  {
11211  temp_entry_p = (*data_p).free;
11212  (*data_p).free = temp_entry_p->link;
11213  temp_entry_p->link = NULL;
11214  }
11215  else
11216  {
11217  /* allocate one */
11218  temp_entry_p = ((FILEIO_BACKUP_INFO_ENTRY *) malloc (sizeof (FILEIO_BACKUP_INFO_ENTRY)));
11219  if (temp_entry_p != NULL)
11220  {
11221  temp_entry_p->link = NULL;
11222  }
11223  else
11224  {
11226  }
11227  }
11228 
11229  return temp_entry_p;
11230 }
11231 
11232 /*
11233  * fileio_clear_backup_info_level () - REMOVES ALL VOLUMES OF A BACKUP LEVEL FROM CACHE
11234  * return:
11235  * level(in): backup level to remove
11236  * dealloc(in): true if the nodes should be freed back to the OS
11237  * which_bkvinf(in):
11238  *
11239  * Note: This routine removes all the nodes for a given level and any levels
11240  * above it. Ordinarily the nodes will be placed on the free list for
11241  * reuse, but if dealloc is true, then the space will be freed.
11242  * Example: IF level 1 is to be cleared, then level 2 is also cleared.
11243  */
11244 int
11245 fileio_clear_backup_info_level (int level, bool is_dealloc, int which_bkvinf)
11246 {
11247  FILEIO_BACKUP_INFO_ENTRY *next_p;
11248  FILEIO_BACKUP_INFO_QUEUE *data_p;
11249  int i;
11250 
11251  data_p = &(fileio_Backup_vol_info_data[which_bkvinf]);
11252  if (level < 0)
11253  {
11254  level = FILEIO_BACKUP_FULL_LEVEL;
11255  }
11256 
11257  /* Delete from the front */
11258  for (i = FILEIO_BACKUP_UNDEFINED_LEVEL - 1; i >= level; i--)
11259  {
11260  while ((*data_p).anchors[i] != NULL)
11261  {
11262  next_p = (*data_p).anchors[i]->link;
11263  if (is_dealloc)
11264  {
11265  free_and_init ((*data_p).anchors[i]);
11266  }
11267  else
11268  {
11269  /* stick it on the free list */
11270  (*data_p).anchors[i]->link = (*data_p).free;
11271  (*data_p).free = (*data_p).anchors[i];
11272  }
11273  (*data_p).anchors[i] = next_p;
11274  }
11275  }
11276 
11277  /* Free the free list nodes if necessary to avoid leaks */
11278  if (is_dealloc)
11279  {
11280  while ((*data_p).free)
11281  {
11282  next_p = (*data_p).free->link;
11283  free_and_init ((*data_p).free);
11284  (*data_p).free = next_p;
11285  }
11286  }
11287 
11288  return NO_ERROR;
11289 }
11290 
11291 /*
11292  * fileio_request_user_response () - REQUEST A RESPONSE VIA REMOVE CLIENT
11293  * return:
11294  * prompt_id(in):
11295  * prompt(in):
11296  * response(in):
11297  * failure_prompt(in):
11298  * range_low(in):
11299  * range_high(in):
11300  * secondary_prompt(in):
11301  * reprompt_value(in):
11302  */
11303 int
11304 fileio_request_user_response (THREAD_ENTRY * thread_p, FILEIO_REMOTE_PROMPT_TYPE prompt_id, const char *prompt_p,
11305  char *response_p, const char *failure_prompt_p, int range_low, int range_high,
11306  const char *secondary_prompt_p, int reprompt_value)
11307 {
11308 #if defined(SERVER_MODE)
11309  char *remote_data_p = NULL;
11310  char *remote_answer_p = NULL;
11311  int data_size;
11312  int remote_status;
11313  char *ptr;
11314 
11315  /* Send the prompt to the client */
11316  if (xio_send_user_prompt_to_client (thread_p, prompt_id, prompt_p, failure_prompt_p, range_low, range_high,
11317  secondary_prompt_p, reprompt_value) != NO_ERROR)
11318  {
11319  return ER_FAILED;
11320  }
11321 
11322  /* Obtain the user's response from the client, without blocking the server. */
11323  if (xs_receive_data_from_client (thread_p, &remote_data_p, &data_size) != NO_ERROR)
11324  {
11325  if (remote_data_p)
11326  {
11327  free_and_init (remote_data_p);
11328  }
11329 
11330  return ER_FAILED;
11331  }
11332 
11333  ptr = or_unpack_int (remote_data_p, &remote_status);
11334  if (remote_status != NO_ERROR)
11335  {
11336  free_and_init (remote_data_p);
11337  return ER_FAILED;
11338  }
11339  data_size -= OR_INT_SIZE;
11340  if (response_p && data_size > 0)
11341  {
11342  /* Otherwise prompt appears successful */
11343  ptr = or_unpack_string_nocopy (ptr, &remote_answer_p);
11344  if (remote_answer_p != NULL)
11345  {
11346  memcpy (response_p, remote_answer_p, intl_mbs_len (remote_answer_p) + 1);
11347  }
11348  }
11349 
11350  free_and_init (remote_data_p);
11351  return NO_ERROR;
11352 #else /* SERVER_MODE */
11353  extern unsigned int db_on_server;
11354 
11355  char new_vol_name[FILEIO_MAX_USER_RESPONSE_SIZE];
11356  char *user_response_p = new_vol_name;
11357  const char *display_string_p;
11358  char line_buf[PATH_MAX * 2];
11359  int pr_status, pr_len;
11360  int x;
11361  int result = 0;
11362  bool is_retry_in = true;
11363  int rc;
11364  char format_string[32];
11365 
11366  /* we're pretending to jump to the client */
11367  db_on_server = 0;
11368  /* Interestingly enough, this is basically the same code as in the ASYNC_ callback has to do remotely. */
11369  display_string_p = prompt_p;
11370  memset (new_vol_name, 0, sizeof (new_vol_name));
11371 
11372  sprintf (format_string, "%%%ds", FILEIO_MAX_USER_RESPONSE_SIZE - 1);
11373 
11374  while (is_retry_in)
11375  {
11376  /* Display prompt, then get user's input. */
11377  fprintf (stdout, display_string_p);
11378 
11379  pr_status = ER_FAILED;
11380  pr_len = 0;
11381  is_retry_in = false;
11382 
11383  if (prompt_id != FILEIO_PROMPT_DISPLAY_ONLY)
11384  {
11385  rc = -1;
11386  if ((fgets (line_buf, PATH_MAX, stdin) != NULL)
11387  && ((rc = sscanf (line_buf, format_string, user_response_p)) > 0))
11388  {
11389 
11390  /* Attempt basic input int validation before we send it back */
11391  switch (prompt_id)
11392  {
11394  /* Numeric range checking */
11395  result = parse_int (&x, user_response_p, 10);
11396  if (result != 0 || x < range_low || x > range_high)
11397  {
11398  fprintf (stdout, failure_prompt_p);
11399  is_retry_in = true;
11400  }
11401  else
11402  {
11403  pr_status = NO_ERROR;
11404  }
11405  break;
11406 
11407  /* attempt simply boolean (y, yes, 1, n, no, 0) validation */
11409  if (char_tolower (*user_response_p) == 'y' || *user_response_p == '1'
11410  || intl_mbs_casecmp ((const char *) user_response_p, "yes") == 0)
11411  {
11412  pr_status = NO_ERROR;
11413  /* convert all affirmate answers into '1' */
11414  strcpy (user_response_p, "1");
11415  }
11416  else
11417  {
11418  pr_status = NO_ERROR;
11419  /* convert all negative answers into '0' */
11420  strcpy (user_response_p, "0");
11421  }
11422  break;
11423 
11424  /* no validation to do */
11426  pr_status = NO_ERROR;
11427  break;
11428 
11429  /* Validate initial prompt, then post secondary prompt */
11431  /* Numeric range checking on the first promp, but user's answer we really want is the second prompt */
11432  result = parse_int (&x, user_response_p, 10);
11433  if (result != 0 || x < range_low || x > range_high)
11434  {
11435  fprintf (stdout, failure_prompt_p);
11436  is_retry_in = true;
11437  }
11438  else if (x == reprompt_value)
11439  {
11440  /* The first answer requires another prompt */
11441  display_string_p = secondary_prompt_p;
11442  is_retry_in = true;
11443  prompt_id = FILEIO_PROMPT_STRING_TYPE;
11444  /* moving the response buffer ptr forward insures that both the first response and the second are
11445  * included in the buffer. (no delimiter or null bytes) */
11446  user_response_p += intl_mbs_len (user_response_p);
11447  }
11448  else
11449  {
11450  /* This answer was sufficient */
11451  pr_status = NO_ERROR;
11452  }
11453 
11454  break;
11455 
11456  default:
11457  /* should we treat this as an error? It is really a protocol error. How do we handle backward
11458  * compatibility for future releases? */
11459  pr_status = NO_ERROR;
11460  }
11461  }
11462  else if (rc == 0)
11463  {
11464  is_retry_in = true;
11465  }
11466  else
11467  {
11468  /* EOF encountered, treat as an error */
11469  return ER_FAILED;
11470  }
11471  }
11472  }
11473 
11474  /* The answer can be returned now. It should be stored in new_vol_name */
11475  /* check for overflow, could be dangerous */
11476  pr_len = intl_mbs_len (new_vol_name);
11477  if (pr_len > FILEIO_MAX_USER_RESPONSE_SIZE)
11478  {
11479  pr_status = ER_FAILED;
11481  }
11482 
11483  /* Copy the answer to the response buffer */
11484  if (response_p)
11485  {
11486  memcpy (response_p, new_vol_name, sizeof (new_vol_name));
11487  }
11488 
11489  db_on_server = 1;
11490  return (pr_status);
11491 #endif /* SERVER_MODE */
11492 }
11493 
11494 #if !defined(WINDOWS)
11495 /*
11496  * fileio_symlink () -
11497  * return:
11498  * src(in):
11499  * dest(in):
11500  * overwrite(in):
11501  */
11502 int
11503 fileio_symlink (const char *src_p, const char *dest_p, int overwrite)
11504 {
11505  if (overwrite && fileio_is_volume_exist (dest_p))
11506  {
11507  unlink (dest_p);
11508  }
11509 
11510  if (symlink (src_p, dest_p) == -1)
11511  {
11513  return ER_FAILED;
11514  }
11515 
11516  return NO_ERROR;
11517 }
11518 
11519 /*
11520  * fileio_lock_region () -
11521  * return:
11522  * fd(in):
11523  * cmd(in):
11524  * type(in):
11525  * offset(in):
11526  * whence(in):
11527  * len(in):
11528  */
11529 static int
11530 fileio_lock_region (int fd, int cmd, int type, off_t offset, int whence, off_t len)
11531 {
11532  struct flock lock;
11533 
11534  lock.l_type = type; /* F_RDLOCK, F_WRLOCK, F_UNLOCK */
11535  lock.l_start = offset; /* byte offset, relative to l_whence */
11536  lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
11537  lock.l_len = len; /* #bytes (O means to EOF) */
11538  return fcntl (fd, cmd, &lock);
11539 }
11540 #endif /* !WINDOWS */
11541 
11542 #if defined(SERVER_MODE)
11543 /*
11544  * fileio_os_sysconf () -
11545  * return:
11546  */
11547 int
11548 fileio_os_sysconf (void)
11549 {
11550  long nprocs = -1;
11551 
11552 #if defined(_SC_NPROCESSORS_ONLN)
11553  nprocs = sysconf (_SC_NPROCESSORS_ONLN);
11554 #elif defined(_SC_NPROC_ONLN)
11555  nprocs = sysconf (_SC_NPROC_ONLN);
11556 #elif defined(_SC_CRAY_NCPU)
11557  nprocs = sysconf (_SC_CRAY_NCPU);
11558 #elif defined(WINDOWS)
11559  {
11560  SYSTEM_INFO sysinfo;
11561  /* determine the base of virtual memory */
11562  GetSystemInfo (&sysinfo);
11563  nprocs = sysinfo.dwNumberOfProcessors;
11564  }
11565 #else /* WINDOWS */
11566  ; /* give up */
11567 #endif /* WINDOWS */
11568  return (nprocs > 1) ? (int) nprocs : 1;
11569 }
11570 #endif /* SERVER_MODE */
11571 
11572 /*
11573  * fileio_initialize_res () -
11574  * return:
11575  */
11576 void
11578 {
11579  fileio_init_lsa_of_page (io_page, page_size);
11580  io_page->prv.pageid = -1;
11581  io_page->prv.volid = -1;
11582 
11583  io_page->prv.ptype = '\0';
11584  io_page->prv.pflag = '\0';
11585  io_page->prv.p_reserve_1 = 0;
11586  io_page->prv.p_reserve_2 = 0;
11587  io_page->prv.tde_nonce = 0;
11588 }
11589 
11590 
11591 /*
11592  * PAGE BITMAP FUNCTIONS
11593  */
11594 
11595 /*
11596  * fileio_page_bitmap_list_init - initialize a page bitmap list
11597  * return: void
11598  * page_bitmap_list(in/out): head of the page bitmap list
11599  */
11600 void
11602 {
11603  assert (page_bitmap_list != NULL);
11604  page_bitmap_list->head = NULL;
11605  page_bitmap_list->tail = NULL;
11606 }
11607 
11608 /*
11609  * fileio_page_bitmap_create - create a page bitmap
11610  * return: page bitmap
11611  * vol_id(in): the number of the page bitmap identification
11612  * total_pages(in): the number of total pages
11613  */
11615 fileio_page_bitmap_create (int vol_id, int total_pages)
11616 {
11618  int page_bitmap_size;
11619 
11620  page_bitmap = (FILEIO_RESTORE_PAGE_BITMAP *) malloc (sizeof (FILEIO_RESTORE_PAGE_BITMAP));
11621  if (page_bitmap == NULL)
11622  {
11624  return NULL;
11625  }
11626 
11627  page_bitmap_size = CEIL_PTVDIV (total_pages, 8);
11628 
11629  page_bitmap->next = NULL;
11630  page_bitmap->vol_id = vol_id;
11631  page_bitmap->size = page_bitmap_size;
11632  page_bitmap->bitmap = (unsigned char *) malloc (page_bitmap_size);
11633  if (page_bitmap->bitmap == NULL)
11634  {
11635  free_and_init (page_bitmap);
11636 
11637  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) page_bitmap_size);
11638  return NULL;
11639  }
11640  memset (page_bitmap->bitmap, 0x0, page_bitmap_size);
11641 
11642  return page_bitmap;
11643 }
11644 
11645 /*
11646  * fileio_page_bitmap_list_find - find the page bitmap which is matched
11647  * with vol_id
11648  * return: pointer of the page bitmap or NULL
11649  * page_bitmap_list(in): head of the page bitmap list
11650  * vol_id(in): the number of the page bitmap identification
11651  */
11654 {
11656 
11657  if (page_bitmap_list->head == NULL)
11658  {
11659  return NULL;
11660  }
11661 
11662  assert (page_bitmap_list->tail != NULL);
11663 
11664  page_bitmap = page_bitmap_list->head;
11665 
11666  while (page_bitmap != NULL)
11667  {
11668  if (page_bitmap->vol_id == vol_id)
11669  {
11670  return page_bitmap;
11671  }
11672  page_bitmap = page_bitmap->next;
11673  }
11674 
11675  return NULL;
11676 }
11677 
11678 /*
11679  * fileio_page_bitmap_list_add - add a page bitmap to a page bitmap list
11680  * page_bitmap_list(in/out): head of the page bitmap list
11681  * page_bitmap(in): pointer of the page bitmap
11682  */
11683 void
11686 {
11687 #if !defined(NDEBUG)
11689 #endif
11690 
11691  assert (page_bitmap_list != NULL);
11692  assert (page_bitmap != NULL);
11693 
11694 #if !defined(NDEBUG)
11695  /* Check the uniqueness of vol_id */
11696  bitmap = page_bitmap_list->head;
11697  while (bitmap != NULL)
11698  {
11699  assert (bitmap->vol_id != page_bitmap->vol_id);
11700  bitmap = bitmap->next;
11701  }
11702 #endif
11703 
11704  if (page_bitmap_list->head == NULL)
11705  {
11706  assert (page_bitmap_list->tail == NULL);
11707 
11708  page_bitmap_list->head = page_bitmap;
11709  page_bitmap_list->tail = page_bitmap;
11710  }
11711  else
11712  {
11713  assert (page_bitmap_list->tail != NULL);
11714 
11715  page_bitmap_list->tail->next = page_bitmap;
11716  page_bitmap_list->tail = page_bitmap;
11717  }
11718 }
11719 
11720 /*
11721  * fileio_page_bitmap_list_destroy - destroy a page bitmap list
11722  * return: void
11723  * page_bitmap_list(in/out): head of the page bitmap list
11724  */
11725 void
11727 {
11729  FILEIO_RESTORE_PAGE_BITMAP *page_bitmap_next = NULL;
11730 
11731  assert (page_bitmap_list != NULL);
11732 
11733  page_bitmap = page_bitmap_list->head;
11734 
11735  while (page_bitmap != NULL)
11736  {
11737  page_bitmap_next = page_bitmap->next;
11738 
11739  page_bitmap->vol_id = 0;
11740  page_bitmap->size = 0;
11741  free_and_init (page_bitmap->bitmap);
11742  free_and_init (page_bitmap);
11743 
11744  page_bitmap = page_bitmap_next;
11745  }
11746  page_bitmap_list->head = NULL;
11747  page_bitmap_list->tail = NULL;
11748 }
11749 
11750 /*
11751  * fileio_page_bitmap_set - set the bit that represents the exitence of the page
11752  * return: void
11753  * page_bitmap(in): pointer of the page bitmap
11754  * page_id(in): position of the page
11755  */
11756 static void
11758 {
11759  assert (page_bitmap != NULL);
11760  assert ((page_bitmap->size - 1) >= (page_id / 8));
11761 
11762  page_bitmap->bitmap[page_id / 8] |= 1 << (page_id % 8);
11763 }
11764 
11765 /*
11766  * fileio_page_bitmap_is_set - get the bit that represents the exitence of the page
11767  * return: if the bit of page is set then it returns true.
11768  * page_bitmap(in): pointer of the page bitmap
11769  * page_id(in): position of the page
11770  */
11771 static bool
11773 {
11774  bool is_set;
11775 
11776  assert (page_bitmap != NULL);
11777  assert ((page_bitmap->size - 1) >= (page_id / 8));
11778 
11779  is_set = page_bitmap->bitmap[page_id / 8] & (1 << (page_id % 8)) ? true : false;
11780 
11781  return is_set;
11782 }
11783 
11784 /*
11785  * fileio_page_bitmap_dump - dump a page bitmap
11786  * return: void
11787  * out_fp(in): FILE stream where to dump; if NULL, stdout
11788  * page_bitmap(in): pointer of the page bitmap
11789  */
11790 static void
11792 {
11793  int i;
11794 
11795  assert (page_bitmap != NULL);
11796 
11797  if (out_fp == NULL)
11798  {
11799  out_fp = stdout;
11800  }
11801 
11802  fprintf (out_fp, "BITMAP_ID = %d, BITMAP_SIZE = %d\n", page_bitmap->vol_id, page_bitmap->size);
11803 
11804  for (i = 0; i < page_bitmap->size; i++)
11805  {
11806  if ((i % 32) == 0)
11807  {
11808  fprintf (out_fp, "%#08X: ", i);
11809  }
11810  else
11811  {
11812  fprintf (out_fp, "%02X ", page_bitmap->bitmap[i]);
11813  }
11814 
11815  if ((i % 32) == 31)
11816  {
11817  fprintf (out_fp, "\n");
11818  }
11819  }
11820  fprintf (out_fp, "\n");
11821 }
11822 
11823 /*
11824  * fileio_page_check_corruption - Check whether the page is corrupted.
11825  * return: error code
11826  * thread_p (in): thread entry
11827  * io_page (in): the page
11828  * is_page_corrupted (out): true, if the page is corrupted.
11829  */
11830 int
11831 fileio_page_check_corruption (THREAD_ENTRY * thread_p, FILEIO_PAGE * io_page, bool * is_page_corrupted)
11832 {
11833  assert (io_page != NULL && is_page_corrupted != NULL);
11834 
11835  *is_page_corrupted = !fileio_is_page_sane (io_page, IO_PAGESIZE);
11836 
11837  return NO_ERROR;
11838 }
11839 
11840 bool
11841 fileio_is_formatted_page (THREAD_ENTRY * thread_p, const char *io_page)
11842 {
11843  char *ref_page;
11844  bool is_formatted = false;
11845 
11846  ref_page = (char *) malloc (IO_PAGESIZE);
11847  if (ref_page == NULL)
11848  {
11850  return false;
11851  }
11852 
11853  memset ((char *) ref_page, 0, IO_PAGESIZE);
11854  (void) fileio_initialize_res (thread_p, (FILEIO_PAGE *) ref_page, IO_PAGESIZE);
11855 
11856  if (memcmp (io_page, ref_page, IO_PAGESIZE) == 0)
11857  {
11858  is_formatted = true;
11859  }
11860 
11861  free_and_init (ref_page);
11862  return is_formatted;
11863 }
#define NUM_NORMAL_TRANS
#define MSGCAT_FILEIO_BKUP_PREV_BKVOL
Definition: file_io.c:155
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
void * fileio_writev(THREAD_ENTRY *thread_p, int vol_fd, void **io_page_array, PAGEID start_page_id, DKNPAGES npages, size_t page_size)
Definition: file_io.c:4412
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
#define ER_IO_DISMOUNT_FAIL
Definition: error_code.h:61
#define ER_IO_LZ4_DECOMPRESS_FAIL
Definition: error_code.h:1119
FILEIO_ZIP_INFO * zip_info
Definition: file_io.h:386
int os_rename_file(const char *src_path, const char *dest_path)
Definition: porting.c:1294
static FILEIO_RELOCATION_VOLUME fileio_find_restore_volume(THREAD_ENTRY *thread_p, const char *dbname, char *to_volname, int unit_num, FILEIO_BACKUP_LEVEL level, int reason)
Definition: file_io.c:10622
static int fileio_synchronize_bg_archive_volume(THREAD_ENTRY *thread_p)
Definition: file_io.c:4531
#define FILEIO_MAX_SUFFIX_LENGTH
Definition: file_io.h:94
#define ER_FAILED_ASSERTION
Definition: error_code.h:695
int unit_num
Definition: file_io.c:345
const VOLID LOG_DBLOG_INFO_VOLID
Definition: log_volids.hpp:45
int page_size
Definition: unloaddb.c:52
#define FILEIO_MAX_WAIT_DBTXT
Definition: file_io.c:175
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
void fileio_unformat_and_rename(THREAD_ENTRY *thread_p, const char *vol_label_p, const char *new_label_p)
Definition: file_io.c:2736
int pageid
Definition: file_io.h:382
int intl_mbs_len(const char *mbs)
Definition: intl_support.c:183
pthread_mutex_t token_mutex
Definition: file_io.h:442
void er_stack_push(void)
static char * fileio_check_file_exist(char *name_p, char *new_guess_path_p, int check_size, int *max_name_size_p)
Definition: file_io.c:5153
bool only_updated_pages
Definition: file_io.h:419
static int fileio_cache(VOLID volid, const char *vlabel, int vdes, FILEIO_LOCKF_TYPE lockf_type)
Definition: file_io.c:5946
const char * vol_label
Definition: file_io.c:397
static int fileio_get_next_backup_volume(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session, bool user_new)
Definition: file_io.c:10803
#define IO_PAGESIZE
static int fileio_initialize_volume_info_cache(void)
Definition: file_io.c:922
#define MSGCAT_FILEIO_DB_MISMATCH
Definition: file_io.c:147
#define FILEIO_VOLLOCK_SUFFIX
Definition: file_io.h:91
void * fileio_write_or_add_to_dwb(THREAD_ENTRY *thread_p, int vol_fd, FILEIO_PAGE *io_page_p, PAGEID page_id, size_t page_size)
Definition: file_io.c:4024
char buf[1]
Definition: file_io.h:367
bool LOG_CS_OWN(THREAD_ENTRY *thread_p)
float rel_disk_compatible(void)
#define ER_IO_LZ4_COMPRESS_FAIL
Definition: error_code.h:1118
int token_consumed
Definition: file_io.h:444
const char * fileio_get_zip_level_string(FILEIO_ZIP_LEVEL zip_level)
Definition: file_io.c:10774
static int fileio_decompress_restore_volume(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session, int nbytes)
Definition: file_io.c:10084
FILEIO_LOCKF_TYPE lockf_type
Definition: file_io.c:386
#define ER_IO_CANNOT_GET_PERMISSION
Definition: error_code.h:1094
FILEIO_BACKUP_INFO_ENTRY * link
Definition: file_io.c:347
unsigned char * bitmap
Definition: file_io.h:266
VOLID volid
Definition: file_io.c:384
static int fileio_get_lock(int fd, const char *vlabel)
Definition: file_io.c:2039
static int fileio_write_backup_header(FILEIO_BACKUP_SESSION *session)
Definition: file_io.c:8887
#define FILEIO_SUFFIX_TMP_LOGARCHIVE
Definition: file_io.h:84
#define MSGCAT_SET_IO
static FILEIO_SYSTEM_VOLUME_INFO * fileio_find_system_volume(THREAD_ENTRY *thread_p, SYS_VOLINFO_APPLY_FN apply_function, APPLY_ARG *arg)
Definition: file_io.c:3554
#define MSGCAT_FILEIO_BKUP_HDR_LEVEL
Definition: file_io.c:137
void LSA_COPY(log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:139
int fileio_reset_volume(THREAD_ENTRY *thread_p, int vol_fd, const char *vlabel, DKNPAGES npages, const LOG_LSA *reset_lsa_p)
Definition: file_io.c:2903
int char_tolower(int c)
Definition: chartype.c:146
char db_next_bkvolname[PATH_MAX]
Definition: file_io.h:313
const char * fileio_get_zip_method_string(FILEIO_ZIP_METHOD zip_method)
Definition: file_io.c:10747
static bool fileio_is_volume_id_equal(THREAD_ENTRY *thread_p, FILEIO_VOLUME_INFO *vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:3524
PAGEID DKNPAGES
#define FILEIO_FIRST_BACKUP_VOL_INFO
Definition: file_io.h:57
#define FILEIO_CHECK_RESTORE_PAGE_ID(area, pagesz)
Definition: file_io.c:231
#define FILEIO_GET_FILE_SIZE(pagesize, npages)
Definition: file_io.c:185
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
static int fileio_increase_flushed_page_count(int npages)
Definition: file_io.c:590
int parse_int(int *ret_p, const char *str_p, int base)
Definition: porting.c:2290
static API_MUTEX mutex
Definition: api_util.c:72
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
FILEIO_REMOTE_PROMPT_TYPE
Definition: file_io.h:128
bool writeable
Definition: file_io.h:383
#define ER_FAILED
Definition: error_code.h:47
unsigned char ptype
Definition: file_io.h:177
#define ER_NET_DATA_TRUNCATED
Definition: error_code.h:268
void fileio_dismount_without_fsync(THREAD_ENTRY *thread_p, int vol_fd)
Definition: file_io.c:3170
static FILEIO_VOLUME_INFO * fileio_reverse_traverse_temporary_volume(THREAD_ENTRY *thread_p, VOLINFO_APPLY_FN apply_function, APPLY_ARG *arg)
Definition: file_io.c:3318
char db_release[REL_MAX_RELEASE_LENGTH]
Definition: file_io.h:295
#define ER_IO_FORMAT_OUT_OF_SPACE
Definition: error_code.h:58
#define FILEIO_DISK_PROTECTION_MODE
Definition: file_io.c:174
static bool fileio_page_bitmap_is_set(FILEIO_RESTORE_PAGE_BITMAP *page_bitmap, int page_id)
Definition: file_io.c:11772
static FILEIO_BACKUP_SESSION * fileio_continue_restore(THREAD_ENTRY *thread_p, const char *db_fullname, INT64 db_creation, FILEIO_BACKUP_SESSION *session, bool first_time, bool authenticate, INT64 match_bkupcreation)
Definition: file_io.c:9335
#define FILEIO_DISK_FORMAT_MODE
Definition: file_io.c:173
void fileio_make_keys_name_given_path(char *keys_name_p, const char *keys_path_p, const char *db_name_p)
Definition: file_io.c:5914
VOLID fileio_find_volume_id_with_label(THREAD_ENTRY *thread_p, const char *vol_label_p)
Definition: file_io.c:6319
VOLID fileio_find_next_perm_volume(THREAD_ENTRY *thread_p, VOLID volid)
Definition: file_io.c:6410
#define ER_IO_GET_LOCK_FAIL
Definition: error_code.h:1096
int fileio_finish_restore(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:9683
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
int fileio_skip_restore_volume(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:10559
static FILEIO_LOCKF_TYPE fileio_get_lockf_type(int vdes)
Definition: file_io.c:6588
const char * vlabel
Definition: file_io.h:329
FILEIO_RELOCATION_VOLUME
Definition: file_io.c:313
bool fileio_is_volume_exist_and_file(const char *vol_label_p)
Definition: file_io.c:5132
#define MSGCAT_FILEIO_RESTORE_FIND_REASON
Definition: file_io.c:153
FILEIO_LOCKF_TYPE fileio_lock_la_log_path(const char *db_full_name_p, const char *lock_path_p, int vol_fd, int *last_deleted_arv_num)
Definition: file_io.c:1392
void fileio_unformat(THREAD_ENTRY *thread_p, const char *vol_label_p)
Definition: file_io.c:2721
#define MSGCAT_FILEIO_LEVEL_MISMATCH
Definition: file_io.c:145
#define FILEIO_VOLINFO_INCREMENT
Definition: file_io.c:302
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
static ssize_t fileio_read_backup(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session, int pageid)
Definition: file_io.c:8723
#define ER_IO_CANNOT_OPEN_VERBOSE_FILE
Definition: error_code.h:1081
#define fileio_unlock_file(fd, offset, whence, len)
Definition: file_io.c:298
VOLID fileio_find_previous_temp_volume(THREAD_ENTRY *thread_p, VOLID volid)
Definition: file_io.c:6458
char name[PATH_MAX]
Definition: file_io.h:330
char vlabel[PATH_MAX]
Definition: file_io.c:337
#define MSGCAT_FILEIO_BKUP_FIND_REASON
Definition: file_io.c:154
STATIC_INLINE void fileio_init_lsa_of_page(FILEIO_PAGE *io_page, PGLENGTH page_size)
Definition: file_io.h:208
#define ASSERT_ERROR_AND_SET(error_code)
static bool fileio_is_system_volume_descriptor_equal(THREAD_ENTRY *thread_p, FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:3571
void thread_sleep(double millisec)
#define assert_release(e)
Definition: error_manager.h:96
#define MSGCAT_LOG_BACKUPINFO_NEEDED
#define ER_CSS_PTHREAD_COND_DESTROY
Definition: error_code.h:1007
#define FILEIO_CHECK_FOR_INTERRUPT_INTERVAL
Definition: file_io.c:190
#define ER_IO_RESTORE_READ_ERROR
Definition: error_code.h:937
static int fileio_make_error_message(THREAD_ENTRY *thread_p, char *error_message_p)
Definition: file_io.c:9291
#define pthread_mutex_unlock(a)
Definition: file_io.c:308
void fileio_flush_control_finalize(void)
Definition: file_io.c:702
INT16 VOLID
#define ER_IO_CANNOT_CHANGE_PERMISSION
Definition: error_code.h:1095
#define ER_CSS_PTHREAD_MUTEX_LOCK
Definition: error_code.h:999
#define ER_IO_MOUNT_LOCKED
Definition: error_code.h:60
const VOLID LOG_DBLOG_ACTIVE_VOLID
Definition: log_volids.hpp:49
static int fileio_flush_control_get_token(THREAD_ENTRY *thread_p, int ntoken)
Definition: file_io.c:731
static FLUSH_STATS fc_Stats
Definition: file_io.c:453
static TOKEN_BUCKET * fc_Token_bucket
Definition: file_io.c:452
int buf_size
Definition: file_io.h:373
#define FILEIO_BACKUP_MINIMUM_NUM_PAGES_FULL_LEVEL
Definition: file_io.c:240
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
static int fileio_initialize_backup_thread(FILEIO_BACKUP_SESSION *session_p, int num_threads)
Definition: file_io.c:6653
unsigned int num_tokens
Definition: file_io.h:454
bool fileio_is_volume_exist(const char *vol_label_p)
Definition: file_io.c:5094
void tsc_elapsed_time_usec(TSCTIMEVAL *tv, TSC_TICKS end_tick, TSC_TICKS start_tick)
Definition: tsc_timer.c:101
const VOLID LOG_MAX_DBVOLID
Definition: log_volids.hpp:34
char * or_unpack_string_nocopy(char *ptr, char **string)
void fileio_remove_all_backup(THREAD_ENTRY *thread_p, int start_level)
Definition: file_io.c:7446
static ssize_t fileio_os_write(THREAD_ENTRY *thread_p, int vol_fd, void *io_page_p, size_t count, off_t offset)
Definition: file_io.c:4087
static bool fileio_dismount_volume(THREAD_ENTRY *thread_p, FILEIO_VOLUME_INFO *vol_info_p, APPLY_ARG *ignore_arg)
Definition: file_io.c:3346
#define MAX_NTRANS
int er_errid(void)
#define FILEIO_BACKUP_NO_ZIP_HEADER_VERSION
Definition: file_io.c:188
#define FILEIO_CHECK_AND_INITIALIZE_VOLUME_HEADER_CACHE(rtn)
Definition: file_io.c:244
#define ER_IO_FORMAT_BAD_NPAGES
Definition: error_code.h:56
#define MSGCAT_FILEIO_MAGIC_MISMATCH
Definition: file_io.c:146
bool fileio_is_temp_volume(THREAD_ENTRY *thread_p, VOLID volid)
Definition: file_io.c:6358
#define GETPID()
Definition: file_io.c:170
static int rv
Definition: file_io.c:309
int pgbuf_flush_control_from_dirty_ratio(void)
STATIC_INLINE void fileio_reset_page_lsa(FILEIO_PAGE *io_page, PGLENGTH page_size)
Definition: file_io.h:217
DKNSECTS fileio_get_number_of_partition_free_sectors(const char *path_p)
Definition: file_io.c:5003
const VOLID LOG_DBLOG_BKUPINFO_VOLID
Definition: log_volids.hpp:47
#define bool
Definition: dbi_compat.h:31
#define MSGCAT_FILEIO_BKUP_HDR_LX_LSA
Definition: file_io.c:152
bool logtb_get_check_interrupt(THREAD_ENTRY *thread_p)
#define FILEIO_BACKUP_FILE_HEADER_PAGE_SIZE
Definition: file_io.c:206
FILEIO_RESTORE_PAGE_BITMAP * head
Definition: file_io.h:272
int fileio_clear_backup_info_level(int level, bool is_dealloc, int which_bkvinf)
Definition: file_io.c:11245
#define FILEIO_SUFFIX_LOGINFO
Definition: file_io.h:85
bool LSA_LT(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:174
#define MSGCAT_FILEIO_BACKUP_VINF_ERROR
Definition: file_io.c:150
#define er_log_debug(...)
ssize_t nread
Definition: file_io.h:384
FILEIO_BACKUP_INFO_ENTRY * free
Definition: file_io.c:355
#define ER_BO_CANNOT_CREATE_LINK
Definition: error_code.h:971
char * getuserid(char *string, int size)
Definition: porting.c:1271
const VOLID LOG_DBCOPY_VOLID
Definition: log_volids.hpp:55
static int fileio_read_restore_header(FILEIO_BACKUP_SESSION *session)
Definition: file_io.c:9191
static VOLID fileio_get_volume_id(int vdes)
Definition: file_io.c:6267
char * fileio_get_volume_label_by_fd(int vol_fd, bool is_peek)
Definition: file_io.c:6254
static FILEIO_LOCKF_TYPE fileio_lock(const char *db_fullname, const char *vlabel, int vdes, bool dowait)
Definition: file_io.c:1179
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
#define FILEIO_PAGE_FLUSH_GROW_RATE
Definition: file_io.c:274
char * fileio_get_directory_path(char *path_p, const char *full_name_p)
Definition: file_io.c:5567
#define NULL_VOLDES
Definition: file_io.h:44
#define VOLID_MAX
static void fileio_make_volume_lock_name(char *vol_lockname, const char *vol_fullname)
Definition: file_io.c:5620
const char * fileio_rename(VOLID vol_id, const char *old_label_p, const char *new_label_p)
Definition: file_io.c:5070
#define FILEIO_BACKUP_VOL_CONT_PAGE_ID
Definition: file_io.c:256
#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
#define FILEIO_USER_NAME_SIZE
Definition: file_io.c:164
unsigned int num_pages
Definition: file_io.h:453
#define MSGCAT_FILEIO_INCORRECT_BKVOLUME
Definition: file_io.c:144
void fileio_page_bitmap_list_init(FILEIO_RESTORE_PAGE_BITMAP_LIST *page_bitmap_list)
Definition: file_io.c:11601
#define MSGCAT_FILEIO_BACKUP_LABEL_INFO
Definition: file_io.c:151
struct fileio_node * next
Definition: file_io.h:381
#define ER_IO_WRITE_OUT_OF_SPACE
Definition: error_code.h:64
FILEIO_BACKUP_PAGE * area
Definition: file_io.h:360
void THREAD_ENTRY
#define ER_BO_CANNOT_CREATE_VOL
Definition: error_code.h:184
#define NULL_PAGEID
int fileio_symlink(const char *src_p, const char *dest_p, int overwrite)
Definition: file_io.c:11503
#define FILEIO_BACKUP_START_PAGE_ID
Definition: file_io.c:252
FILEIO_WRITE_MODE
Definition: file_io.h:164
static int fileio_initialize_backup_info(int which_bkvinf)
Definition: file_io.c:11164
static int fileio_flush_control_get_desired_rate(TOKEN_BUCKET *tb)
Definition: file_io.c:881
#define MSGCAT_SET_LOG
int size
Definition: file_io.h:265
#define ER_IO_READ
Definition: error_code.h:62
#define MSGCAT_FILEIO_BKUP_HDR_BKUP_PAGESIZE
Definition: file_io.c:157
UINT64 prm_get_bigint_value(PARAM_ID prm_id)
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
#define ER_IO_FORMAT_FAIL
Definition: error_code.h:57
#define VPID_SET(vpid_ptr, volid_value, pageid_value)
Definition: dbtype_def.h:899
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
int fileio_find_volume_descriptor_with_label(const char *vol_label_p)
Definition: file_io.c:6544
static void fileio_check_lockby_file(char *name_info_lock_p)
Definition: file_io.c:1763
void css_push_external_task(CSS_CONN_ENTRY *conn, cubthread::entry_task *task)
int fileio_get_volume_max_suffix(void)
Definition: file_io.c:5604
#define ER_IO_RELEASE_LOCK_FAIL
Definition: error_code.h:1097
static bool fileio_is_terminated_process(int pid)
Definition: file_io.c:1141
char * fileio_get_volume_label(VOLID vol_id, bool is_peek)
Definition: file_io.c:6182
static ssize_t fileio_os_read(THREAD_ENTRY *thread_p, int vol_fd, void *io_page_p, size_t count, off_t offset)
Definition: file_io.c:3885
static bool fileio_is_volume_label_equal(THREAD_ENTRY *thread_p, FILEIO_VOLUME_INFO *vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:6307
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
const char * fileio_get_base_file_name(const char *full_name_p)
Definition: file_io.c:5533
#define assert(x)
static char * fileio_ctime(INT64 *clock, char *buf)
Definition: file_io.c:1118
FILEIO_ZIP_LEVEL
Definition: file_io.h:113
const VOLID LOG_DBFIRST_VOLID
Definition: log_volids.hpp:38
#define FILEIO_BACKUP_HEADER_IO_SIZE
Definition: file_io.c:184
#define FILEIO_VOLEXT_PREFIX
Definition: file_io.h:88
int prm_get_integer_value(PARAM_ID prm_id)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
#define FILEIO_BACKUP_MINIMUM_NUM_PAGES
Definition: file_io.c:237
void fileio_make_volume_temp_name(char *vol_tmp_full_name_p, const char *tmp_path_p, const char *tmp_name_p, VOLID vol_id)
Definition: file_io.c:5690
#define MSGCAT_FILEIO_BKUP_HDR_TIME
Definition: file_io.c:138
std::chrono::high_resolution_clock clock
Definition: perf_def.hpp:39
void fileio_close(int vol_fd)
Definition: file_io.c:2078
#define CUBRID_MAGIC_MAX_LENGTH
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
int fileio_get_number_of_partition_free_pages(const char *path_p, size_t page_size)
Definition: file_io.c:4937
void fileio_page_bitmap_list_destroy(FILEIO_RESTORE_PAGE_BITMAP_LIST *page_bitmap_list)
Definition: file_io.c:11726
char db_prec_bkvolname[PATH_MAX]
Definition: file_io.h:310
void fileio_abort_backup(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p, bool does_unformat_bk)
Definition: file_io.c:7052
int tokens
Definition: file_io.h:443
#define MSGCAT_FILEIO_BKUP_FILE
Definition: file_io.c:139
static char * fileio_check_file_is_same(char *name_p, char *new_guess_path_p, int check_size, int *max_name_size_p, struct stat *buf)
Definition: file_io.c:5193
const char * vlabel
Definition: file_io.h:356
#define DB_INT32_MAX
Definition: dbtype_def.h:633
#define IO_SECTORSIZE
#define MSGCAT_FILEIO_REST_RELO_NEEDED
Definition: file_io.c:140
#define FILEIO_SUFFIX_BACKUP_VOLINFO
Definition: file_io.h:87
#define DB_MAX_IDENTIFIER_LENGTH
Definition: dbtype_def.h:495
static int fileio_write_backup(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session, ssize_t towrite_nbytes)
Definition: file_io.c:8834
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
#define CUBRID_MAGIC_DATABASE_BACKUP
#define CUBRID_MAGIC_DATABASE_BACKUP_OLD
static enum scanner_mode mode
#define FILEIO_RESTORE_DBVOLS_IO_PAGE_SIZE(sess)
Definition: file_io.c:200
static void fileio_unlock(const char *vlabel, int vdes, FILEIO_LOCKF_TYPE lockf_type)
Definition: file_io.c:1821
#define MSGCAT_FILEIO_NEWLOCATION
Definition: file_io.c:142
bool pgbuf_is_log_check_for_interrupts(THREAD_ENTRY *thread_p)
Definition: page_buffer.c:4762
#define pthread_mutex_lock(a)
Definition: file_io.c:307
static void fileio_write_backup_end_time_to_last_page(FILEIO_BACKUP_SESSION *session_p, INT64 end_time)
Definition: file_io.c:7307
static FILEIO_VOLUME_INFO * fileio_traverse_permanent_volume(THREAD_ENTRY *thread_p, VOLINFO_APPLY_FN apply_function, APPLY_ARG *arg)
Definition: file_io.c:3237
FILEIO_NODE * tail
Definition: file_io.h:394
FILE * verbose_fp
Definition: file_io.h:435
unsigned int num_log_pages
Definition: file_io.h:452
#define MSGCAT_FILEIO_BACKUP_TIME_MISMATCH
Definition: file_io.c:149
int asprintf(char **ptr, const char *format,...)
Definition: porting.c:973
static FILEIO_NODE * fileio_delete_queue_head(FILEIO_QUEUE *qp)
Definition: file_io.c:7630
int cub_dirname_r(const char *path, char *pathbuf, size_t buflen)
Definition: porting.c:989
void fileio_dismount(THREAD_ENTRY *thread_p, int vol_fd)
Definition: file_io.c:3134
bool rel_is_log_compatible(const char *writer_rel_str, const char *reader_rel_str)
static int fileio_Flushed_page_count
Definition: file_io.c:449
FILEIO_TYPE io_type
Definition: file_io.h:416
const char * rel_name(void)
static pthread_mutex_t fileio_Flushed_page_counter_mutex
Definition: file_io.c:447
std::int64_t pageid
Definition: log_lsa.hpp:36
int fileio_synchronize_all(THREAD_ENTRY *thread_p, bool is_include)
Definition: file_io.c:4618
#define MSGCAT_FILEIO_BKUP_NEXT_BKVOL
Definition: file_io.c:156
void logpb_debug_check_log_page(THREAD_ENTRY *thread_p, void *log_pgptr_ptr)
FILEIO_BACKUP_SESSION * fileio_finish_backup(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:7336
void fileio_dismount_all(THREAD_ENTRY *thread_p)
Definition: file_io.c:3374
bool(* VOLINFO_APPLY_FN)(THREAD_ENTRY *thread_p, FILEIO_VOLUME_INFO *vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:417
FILEIO_LOCKF_TYPE
Definition: file_io.h:151
#define FILEIO_SUFFIX_KEYS
Definition: file_io.h:93
#define pthread_mutex_destroy(a)
Definition: file_io.c:306
#define NULL
Definition: freelistheap.h:34
#define FILEIO_VOLTMP_PREFIX
Definition: file_io.h:89
FILEIO_ZIP_PAGE zip_page
Definition: file_io.h:374
#define FILEIO_VOLINFO_SUFFIX
Definition: file_io.h:90
FILEIO_RESTORE_PAGE_BITMAP * tail
Definition: file_io.h:273
#define CTIME_MAX
Definition: porting.h:72
#define strncpy_bufsize(buf, str)
Definition: porting.h:340
static int fileio_flush_backup(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session)
Definition: file_io.c:8577
#define FILEIO_BACKUP_PAGE_OVERHEAD
Definition: file_io.c:193
const char * er_msg(void)
static int fileio_compress_backup_node(FILEIO_NODE *node, FILEIO_BACKUP_HEADER *backup_hdr)
Definition: file_io.c:7660
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
static FILEIO_SYSTEM_VOLUME_HEADER fileio_Sys_vol_info_header
Definition: file_io.c:421
pid_t pid
Definition: dynamic_load.c:955
union fileio_apply_function_arg APPLY_ARG
static char * dbname
void tsc_getticks(TSC_TICKS *tck)
Definition: tsc_timer.c:81
STATIC_INLINE void fileio_set_page_lsa(FILEIO_PAGE *io_page, const LOG_LSA *lsa, PGLENGTH page_size)
Definition: file_io.h:227
int xio_send_user_prompt_to_client(THREAD_ENTRY *thread_p, FILEIO_REMOTE_PROMPT_TYPE prompt_id, const char *prompt, const char *failure_prompt, int range_low, int range_high, const char *secondary_prompt, int reprompt_value)
#define FILEIO_MAX_USER_RESPONSE_SIZE
Definition: file_io.h:50
char vlabel[PATH_MAX]
Definition: file_io.c:390
#define ER_IO_MOUNT_FAIL
Definition: error_code.h:59
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
static FILEIO_VOLUME_INFO * fileio_reverse_traverse_permanent_volume(THREAD_ENTRY *thread_p, VOLINFO_APPLY_FN apply_function, APPLY_ARG *arg)
Definition: file_io.c:3263
void fileio_finalize_backup_info(int which_bkvinf)
Definition: file_io.c:11143
#define FILEIO_SET_BACKUP_PAGE_ID(area, pageid, psize)
Definition: file_io.c:215
static int fileio_release_lock(int fd)
Definition: file_io.c:2058
float db_compatibility
Definition: file_io.h:290
static void fileio_finalize_backup_thread(FILEIO_BACKUP_SESSION *session_p, FILEIO_ZIP_METHOD zip_method)
Definition: file_io.c:6963
#define err(fd,...)
Definition: porting.h:431
#define ER_PB_BAD_PAGEID
Definition: error_code.h:67
int fileio_set_permission(const char *vol_label_p)
Definition: file_io.c:2002
static int fileio_write_backup_node(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session, FILEIO_NODE *node, FILEIO_BACKUP_HEADER *backup_hdr)
Definition: file_io.c:7743
#define VOL_MAX_NPAGES(page_size)
static int fileio_write_backup_end_time_to_header(FILEIO_BACKUP_SESSION *session_p, INT64 end_time)
Definition: file_io.c:7255
#define FILEIO_BACKUP_FILE_END_PAGE_ID
Definition: file_io.c:255
FILEIO_BACKUP_LEVEL level
Definition: file_io.h:298
char * or_unpack_int(char *ptr, int *number)
FILEIO_BACKUP_LEVEL level
Definition: file_io.h:349
#define FILEIO_BACKUP_FILE_START_PAGE_ID
Definition: file_io.c:254
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
#define ONE_M
Definition: porting.h:63
pthread_cond_t waiter_cond
Definition: file_io.h:446
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
CSS_CONN_ENTRY * css_get_current_conn_entry(void)
#define FILEIO_PAGE_FLUSH_DROP_RATE
Definition: file_io.c:276
FILEIO_VOLUME_INFO ** volinfo
Definition: file_io.c:414
unsigned char pflag
Definition: file_io.h:178
FILEIO_SYNC_OPTION
Definition: file_io.h:158
#define CEIL_PTVDIV(dividend, divisor)
Definition: memory_alloc.h:50
LOG_LSA last_chkpt_lsa
Definition: file_io.h:327
char * db_name
const VOLID LOG_DBDWB_VOLID
Definition: log_volids.hpp:57
void er_set_with_oserror(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
void fileio_make_keys_name(char *keys_name_p, const char *db_full_name_p)
Definition: file_io.c:5897
#define MSGCAT_CATALOG_CUBRID
FILEIO_ZIP_LEVEL zip_level
Definition: file_io.h:317
static int fileio_read_restore(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session, int toread_nbytes)
Definition: file_io.c:8996
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_CSS_PTHREAD_MUTEX_DESTROY
Definition: error_code.h:998
#define MSGCAT_FILEIO_INPUT_RANGE_ERROR
Definition: file_io.c:143
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
#define ER_IO_WRITE
Definition: error_code.h:63
FILEIO_SYSTEM_VOLUME_INFO anchor
Definition: file_io.c:378
FILEIO_LOCKF_TYPE lockf_type
Definition: file_io.c:363
#define ER_MNT_WAITING_THREAD
Definition: error_code.h:1226
#define ER_IO_RESTORE_PAGEID_OUTOF_BOUNDS
Definition: error_code.h:938
void er_stack_pop(void)
#define FILEIO_SET_BACKUP_PAGE_ID_COPY(area, pageid, psize)
Definition: file_io.c:210
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
static bool fileio_is_system_volume_id_equal(THREAD_ENTRY *thread_p, FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:3578
void fileio_abort_restore(THREAD_ENTRY *thread_p, FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:8980
int xs_receive_data_from_client(THREAD_ENTRY *thread_p, char **area, int *datasize)
#define CAST_BUFLEN
Definition: porting.h:471
const char * envvar_get(const char *name)
static int fileio_allocate_and_initialize_volume_info(FILEIO_VOLUME_HEADER *header_p, int idx)
Definition: file_io.c:988
bool LOG_CS_OWN_WRITE_MODE(THREAD_ENTRY *thread_p)
static void error(const char *msg)
Definition: gencat.c:331
bool fileio_is_permanent_volume_descriptor(THREAD_ENTRY *thread_p, int vol_fd)
Definition: file_io.c:6387
static FILEIO_BACKUP_SESSION * fileio_initialize_restore(THREAD_ENTRY *thread_p, const char *db_fullname, char *backup_src, FILEIO_BACKUP_SESSION *session, FILEIO_BACKUP_LEVEL level, const char *restore_verbose_file_path, bool newvolpath)
Definition: file_io.c:8944
#define FILEIO_SUFFIX_LOGARCHIVE
Definition: file_io.h:83
#define ER_IO_NOT_A_BACKUP_OF_GIVEN_DATABASE
Definition: error_code.h:765
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 FILEIO_BACKUP_CURRENT_HEADER_VERSION
Definition: file_io.c:189
static int fileio_fill_hole_during_restore(THREAD_ENTRY *thread_p, int *next_pageid, int stop_pageid, FILEIO_BACKUP_SESSION *session, FILEIO_RESTORE_PAGE_BITMAP *page_bitmap)
Definition: file_io.c:10035
static int rc
Definition: serial.c:50
#define FI_TEST(th, code, state)
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
static bool fileio_is_volume_id_lt(THREAD_ENTRY *thread_p, FILEIO_VOLUME_INFO *vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:3544
#define ER_INTERRUPTED
Definition: error_code.h:51
unsigned int db_on_server
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_BO_DIRECTORY_DOESNOT_EXIST
Definition: error_code.h:1269
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
#define FILEIO_BACKUP_END_PAGE_ID
Definition: file_io.c:253
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
#define fileio_lock_file_write(fd, offset, whence, len)
Definition: file_io.c:294
static FILEIO_VOLUME_INFO * fileio_traverse_temporary_volume(THREAD_ENTRY *thread_p, VOLINFO_APPLY_FN apply_function, APPLY_ARG *arg)
Definition: file_io.c:3289
#define ER_LOG_BKUP_INCOMPATIBLE
Definition: error_code.h:781
PGLENGTH db_iopagesize
Definition: file_io.h:297
FILEIO_LOCKF_TYPE fileio_unlock_la_dbname(int *lockf_vdes, char *db_name, bool clear_owner)
Definition: file_io.c:1691
#define ARG_FILE_LINE
Definition: error_manager.h:44
int fileio_expand_to(THREAD_ENTRY *thread_p, VOLID vol_id, DKNPAGES size_npages, DB_VOLTYPE voltype)
Definition: file_io.c:2512
void er_print_callstack(const char *file_name, const int line_no, const char *fmt,...)
bool(* SYS_VOLINFO_APPLY_FN)(THREAD_ENTRY *thread_p, FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:418
FILEIO_PAGE iopage
Definition: file_io.h:249
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
static int fileio_expand_permanent_volume_info(FILEIO_VOLUME_HEADER *header, int volid)
Definition: file_io.c:1029
char * envvar_vardir_file(char *path, size_t size, const char *filename)
DB_VOLTYPE
Definition: dbtype_def.h:192
int fileio_synchronize(THREAD_ENTRY *thread_p, int vol_fd, const char *vlabel, FILEIO_SYNC_OPTION sync_dwb)
Definition: file_io.c:4441
int fileio_list_restore(THREAD_ENTRY *thread_p, const char *db_full_name_p, char *backup_source_p, FILEIO_BACKUP_LEVEL level, bool is_new_vol_path)
Definition: file_io.c:9703
INT16 PGLENGTH
DKNPAGES fileio_get_number_of_volume_pages(int vol_fd, size_t page_size)
Definition: file_io.c:4918
#define DISK_VOLHEADER_PAGE
Definition: disk_manager.h:35
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
#define pthread_mutex_init(a, b)
Definition: file_io.c:305
#define FILEIO_MIN_FLUSH_PAGES_PER_SEC
Definition: file_io.c:261
static int fileio_min_temporary_volumes(int index, int num_temp_volums, int num_volinfo_array)
Definition: file_io.c:3202
static int fileio_get_primitive_way_max(const char *path, long int *filename_max, long int *pathname_max)
Definition: file_io.c:5227
static int fileio_create(THREAD_ENTRY *thread_p, const char *db_fullname, const char *vlabel, VOLID volid, bool dolock, bool dosync)
Definition: file_io.c:2104
static FILEIO_SYSTEM_VOLUME_INFO * fileio_traverse_system_volume(THREAD_ENTRY *thread_p, SYS_VOLINFO_APPLY_FN apply_function, APPLY_ARG *arg)
Definition: file_io.c:3215
FILEIO_BACKUP_RECORD_INFO previnfo[FILEIO_BACKUP_UNDEFINED_LEVEL]
Definition: file_io.h:307
FILEIO_NODE * free_list
Definition: file_io.h:395
#define MSGCAT_FILEIO_REST_RELO_OPTIONS
Definition: file_io.c:141
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define LOG_ISRESTARTED()
Definition: log_impl.h:232
static void fileio_decache(THREAD_ENTRY *thread_p, int vdes)
Definition: file_io.c:6065
#define strlen(s1)
Definition: intl_support.c:43
VOLID fileio_find_previous_perm_volume(THREAD_ENTRY *thread_p, VOLID volid)
Definition: file_io.c:6434
#define ER_IO_NOT_A_BACKUP
Definition: error_code.h:764
char bkvol_name[PATH_MAX]
Definition: file_io.c:346
void LSA_SET_NULL(log_lsa *lsa_ptr)
Definition: log_lsa.hpp:146
#define ER_IO_BKUP_DATABASE_VOLUME_OR_FILE_EXPECTED
Definition: error_code.h:766
#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
#define FI_INSERTED(code)
void fileio_make_dwb_name(char *dwb_name_p, const char *dwb_path_p, const char *db_name_p)
Definition: file_io.c:5881
static TOKEN_BUCKET fc_Token_bucket_s
Definition: file_io.c:451
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
#define DB_PAGESIZE
static void * fileio_write_restore(THREAD_ENTRY *thread_p, FILEIO_RESTORE_PAGE_BITMAP *page_bitmap, int vdes, void *io_pgptr, VOLID vol_id, PAGEID page_id, FILEIO_BACKUP_LEVEL level)
Definition: file_io.c:10506
FILEIO_BACKUP_TYPE type
Definition: file_io.h:431
FILEIO_LOCKF_TYPE fileio_lock_la_dbname(int *lockf_vdes, char *db_name, char *log_path)
Definition: file_io.c:1545
void fileio_make_volume_ext_given_name(char *vol_ext_full_name_p, const char *ext_path_p, const char *ext_name_p)
Definition: file_io.c:5672
#define MSGCAT_FILEIO_BKUP_HDR_DBINFO
Definition: file_io.c:136
static bool fileio_is_volume_descriptor_equal(THREAD_ENTRY *thread_p, FILEIO_VOLUME_INFO *vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:3514
FILEIO_THREAD_INFO read_thread_info
Definition: file_io.h:434
#define FILEIO_GET_BACKUP_PAGE_ID(area)
Definition: file_io.c:223
bool prm_get_bool_value(PARAM_ID prm_id)
#define ER_CSS_PTHREAD_MUTEX_UNLOCK
Definition: error_code.h:1001
#define MSGCAT_FILEIO_BKUP_HDR_INC_ACTIVELOG
Definition: file_io.c:159
int intl_mbs_casecmp(const char *mbs1, const char *mbs2)
Definition: intl_support.c:358
#define FALSE
Definition: broker_admin.c:50
#define MSGCAT_LOG_NEWLOCATION
#define ER_BO_CWD_FAIL
Definition: error_code.h:179
void fileio_page_hexa_dump(const char *src_data, int length)
Definition: file_io.c:3597
FILEIO_TYPE
Definition: file_io.h:138
static void fileio_page_bitmap_dump(FILE *out_fp, const FILEIO_RESTORE_PAGE_BITMAP *page_bitmap)
Definition: file_io.c:11791
static void fileio_read_backup_end_time_from_last_page(FILEIO_BACKUP_SESSION *session_p)
Definition: file_io.c:7322
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
static int fileio_expand_temporary_volume_info(FILEIO_VOLUME_HEADER *header, int volid)
Definition: file_io.c:1074
struct fileio_node * prev
Definition: file_io.h:380
int i
Definition: dynamic_load.c:954
int dwb_flush_force(THREAD_ENTRY *thread_p, bool *all_sync)
char loc_db_fullname[PATH_MAX]
Definition: file_io.h:325
char * msgcat_message(int cat_id, int set_id, int msg_id)
static ssize_t pwrite_with_injected_fault(THREAD_ENTRY *thread_p, int fd, const void *buf, size_t count, off_t offset)
Definition: file_io.c:3639
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
#define MSGCAT_FILEIO_BKUP_HDR
Definition: file_io.c:133
static const char * fileio_get_backup_level_string(FILEIO_BACKUP_LEVEL level)
Definition: file_io.c:10723
static FILEIO_NODE * fileio_allocate_node(FILEIO_QUEUE *qp, FILEIO_BACKUP_HEADER *backup_hdr)
Definition: file_io.c:7495
char log_path[PATH_MAX]
Definition: file_io.h:326
while(1)
Definition: cnvlex.c:816
FILEIO_BACKUP_PAGE * area
Definition: file_io.h:385
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
for(p=libs;*p;p++)
Definition: dynamic_load.c:968
static int fileio_create_backup_volume(THREAD_ENTRY *thread_p, const char *db_fullname, const char *vlabel, VOLID volid, bool dolock, bool dosync, int atleast_pages)
Definition: file_io.c:2236
static bool fileio_synchronize_volume(THREAD_ENTRY *thread_p, FILEIO_VOLUME_INFO *vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:4584
void * fileio_initialize_pages(THREAD_ENTRY *thread_p, int vol_fd, FILEIO_PAGE *io_page_p, DKNPAGES start_pageid, DKNPAGES npages, size_t page_size, int kbytes_to_be_written_per_sec)
Definition: file_io.c:1864
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
#define FILEIO_SUFFIX_LOGACTIVE
Definition: file_io.h:82
void fileio_initialize_res(THREAD_ENTRY *thread_p, FILEIO_PAGE *io_page, PGLENGTH page_size)
Definition: file_io.c:11577
STATIC_INLINE void perfmon_add_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid, UINT64 amount) __attribute__((ALWAYS_INLINE))
char * strdup(const char *str)
Definition: porting.c:901
#define NULL_VOLID
#define FILEIO_PATH_SEPARATOR(path)
Definition: file_io.h:78
STATIC_INLINE int fileio_is_page_sane(FILEIO_PAGE *io_page, PGLENGTH page_size)
Definition: file_io.h:237
FILEIO_BACKUP_BUFFER bkup
Definition: file_io.h:432
static void fileio_compensate_flush(THREAD_ENTRY *thread_p, int fd, int npage)
Definition: file_io.c:607
static bool fileio_synchronize_sys_volume(THREAD_ENTRY *thread_p, FILEIO_SYSTEM_VOLUME_INFO *vol_sys_info_p, APPLY_ARG *arg)
Definition: file_io.c:4546
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
static bool fileio_is_volume_id_gt(THREAD_ENTRY *thread_p, FILEIO_VOLUME_INFO *vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:3534
char page[1]
Definition: file_io.h:195
_exit(1)
int vol_id
Definition: file_io.h:264
FILEIO_NODE * head
Definition: file_io.h:393
#define ER_IO_SYNC
Definition: error_code.h:714
FILEIO_SYSTEM_VOLUME_INFO * next
Definition: file_io.c:368
INT32 PAGEID
#define ER_IO_EXPAND_OUT_OF_SPACE
Definition: error_code.h:868
#define ER_LOG_RECOVER_ON_OLD_RELEASE
Definition: error_code.h:146
#define FILEIO_SUFFIX_DWB
Definition: file_io.h:92
static FILEIO_BACKUP_INFO_QUEUE fileio_Backup_vol_info_data[2]
Definition: file_io.c:442
static int fileio_lock_region(int fd, int cmd, int type, off_t offset, int whence, off_t len)
Definition: file_io.c:11530
#define CUB_MAXHOSTNAMELEN
Definition: porting.h:379
char vlabel[PATH_MAX]
Definition: file_io.c:364
const char * rel_release_string(void)
#define ER_CSS_PTHREAD_MUTEX_INIT
Definition: error_code.h:997
#define FILEIO_DBVOLS_IO_PAGE_SIZE(backup_header_p)
Definition: file_io.c:203
#define MSGCAT_FILEIO_UNIT_NUM_MISMATCH
Definition: file_io.c:148
int dwb_add_page(THREAD_ENTRY *thread_p, FILEIO_PAGE *io_page_p, VPID *vpid, DWB_SLOT **p_dwb_slot)
static char * host
FILEIO_PAGE_RESERVED prv
Definition: file_io.h:194
static FILEIO_NODE * fileio_free_node(FILEIO_QUEUE *qp, FILEIO_NODE *node)
Definition: file_io.c:7580
static FILEIO_VOLUME_HEADER fileio_Vol_info_header
Definition: file_io.c:434
static bool fileio_is_system_volume_label_equal(THREAD_ENTRY *thread_p, FILEIO_SYSTEM_VOLUME_INFO *sys_vol_info_p, APPLY_ARG *arg)
Definition: file_io.c:3584
static int fileio_max_permanent_volumes(int index, int num_permanent_volums)
Definition: file_io.c:3189
#define PEEK
Definition: file_io.h:74
#define MSGCAT_FILEIO_BKUP_HDR_RELEASES
Definition: file_io.c:135
#define FILEIO_BACKUP_NUM_THREADS_AUTO
Definition: file_io.h:59
SECTID DKNSECTS
#define MONITOR_WAITING_THREAD(elapsed)
int fileio_flush_control_initialize(void)
Definition: file_io.c:658
static FILEIO_BACKUP_INFO_ENTRY * fileio_allocate_backup_info(int which_bkvinf)
Definition: file_io.c:11197
FILEIO_BACKUP_LEVEL
Definition: file_io.h:96
FILEIO_QUEUE io_queue
Definition: file_io.h:425
FILEIO_ZIP_METHOD
Definition: file_io.h:104
int fileio_open(const char *vol_label_p, int flags, int mode)
Definition: file_io.c:1957
#define ER_CSS_PTHREAD_COND_INIT
Definition: error_code.h:1006
int fileio_page_check_corruption(THREAD_ENTRY *thread_p, FILEIO_PAGE *io_page, bool *is_page_corrupted)
Definition: file_io.c:11831
#define PATH_SEPARATOR
Definition: porting.h:347
void fileio_make_volume_info_name(char *vol_info_name_p, const char *db_full_name_p)
Definition: file_io.c:5636
bool fileio_is_formatted_page(THREAD_ENTRY *thread_p, const char *io_page)
Definition: file_io.c:11841
FILEIO_ZIP_METHOD zip_method
Definition: file_io.h:316
std::int64_t offset
Definition: log_lsa.hpp:37
#define MSGCAT_LOG_STARTS
#define FILEIO_SUFFIX_BACKUP
Definition: file_io.h:86
#define GETHOSTNAME(p, l)
Definition: porting.h:381
const char ** p
Definition: dynamic_load.c:945
FILEIO_RESTORE_PAGE_BITMAP * next
Definition: file_io.h:263
#define fileio_lock_file_read(fd, offset, whence, len)
Definition: file_io.c:290
static void fileio_page_bitmap_set(FILEIO_RESTORE_PAGE_BITMAP *page_bitmap, int page_id)
Definition: file_io.c:11757
char magic[CUBRID_MAGIC_MAX_LENGTH]
Definition: file_io.h:289
#define ER_IO_RENAME_FAIL
Definition: error_code.h:65
#define ER_IO_TRUNCATE
Definition: error_code.h:1070
bool fileio_map_mounted(THREAD_ENTRY *thread_p, bool(*fun)(THREAD_ENTRY *thread_p, VOLID vol_id, void *args), void *args)
Definition: file_io.c:3463
#define MSGCAT_FILEIO_BKUP_HDR_ZIP_INFO
Definition: file_io.c:158
#define MSGCAT_FILEIO_STARTS
Definition: file_io.c:131
#define FILEIO_FULL_LEVEL_EXP
Definition: file_io.c:176
Definition: file_io.c:343
#define OFF_T_MAX
Definition: porting.h:475
int fileio_get_volume_descriptor(VOLID vol_id)
Definition: file_io.c:6488
int fileio_flush_control_add_tokens(THREAD_ENTRY *thread_p, INT64 diff_usec, int *token_gen, int *token_consumed)
Definition: file_io.c:819
char db_fullname[PATH_MAX]
Definition: file_io.h:296