CUBRID Engine  latest
file_manager.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * file_manager.c - file manager
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stddef.h>
30 #include <string.h>
31 #include <time.h>
32 
33 #include "file_manager.h"
34 
35 #include "btree.h"
36 #include "porting.h"
37 #include "porting_inline.hpp"
38 #include "memory_alloc.h"
39 #include "storage_common.h"
40 #include "error_manager.h"
41 #include "file_io.h"
42 #include "page_buffer.h"
43 #include "disk_manager.h"
44 #include "log_append.hpp"
45 #include "log_manager.h"
46 #include "log_impl.h"
47 #include "log_lsa.hpp"
48 #include "lock_manager.h"
49 #include "system_parameter.h"
50 #include "boot_sr.h"
51 #include "memory_hash.h"
52 #include "environment_variable.h"
53 #include "xserver_interface.h"
54 #include "oid.h"
55 #include "heap_file.h"
56 #include "bit.h"
57 #include "util_func.h"
58 #include "vacuum.h"
59 #include "btree_load.h"
60 #include "critical_section.h"
61 #if defined(SERVER_MODE)
62 #include "connection_error.h"
63 #endif /* SERVER_MODE */
64 #include "fault_injection.h"
65 #include "thread_manager.hpp" // for thread_get_thread_entry_info
66 
67 /************************************************************************/
68 /* Define structures, globals, and macro's */
69 /************************************************************************/
70 
71 /************************************************************************/
72 /* File manager section */
73 /************************************************************************/
74 
75 /************************************************************************/
76 /* File header section */
77 /************************************************************************/
78 
79 /* FILE_HEADER -
80  * This structure keeps meta-data on files in the file header page. The rest of the file header page, based on the type
81  * of files, is used by other tables.
82  */
83 typedef struct file_header FILE_HEADER;
85 {
86  INT64 time_creation; /* Time of file creation. */
87 
88  VFID self; /* Self VFID */
89  FILE_TABLESPACE tablespace; /* The table space definition */
90  FILE_DESCRIPTORS descriptor; /* File descriptor. Depends on file type. */
91 
92  /* Page counts. */
93  int n_page_total; /* File total page count. */
94  int n_page_user; /* User page count. */
95  int n_page_ftab; /* Page count used for file tables. */
96  int n_page_free; /* Free page count. Pages that were reserved on disk and can be allocated by user (or
97  * table) in the future. */
98  int n_page_mark_delete; /* used by numerable files to track marked deleted pages */
99 
100  /* Sector counts. */
101  int n_sector_total; /* File total sector count. */
102  int n_sector_partial; /* Partially allocated sectors count. */
103  int n_sector_full; /* Fully allocated sectors count. */
104  int n_sector_empty; /* Completely empty sectors count. Empty sectors are also considered partially
105  * allocated (so this is less or equal to n_sector_partial. */
106 
107  FILE_TYPE type; /* File type. */
108 
109  INT32 file_flags; /* File flags. */
110 
111  VOLID volid_last_expand; /* Last volume used for expansion. */
112 
113  INT16 offset_to_partial_ftab; /* Offset to partial sectors table. */
114  INT16 offset_to_full_ftab; /* Offset to full sectors table. */
115  INT16 offset_to_user_page_ftab; /* Offset to user pages table. */
116 
117  VPID vpid_sticky_first; /* VPID of first page (if it is sticky). This page should never be deallocated. */
118 
119  /* Temporary files. */
120  /* Temporary files are handled differently than permanent files for simplicity. Temporary file pages are never
121  * deallocated, they are deallocated when the file is destroyed or reclaimed when file is reset (but kept in cache).
122  * Therefore, we can just keep a cursor that tracks the location of last allocated page. This cursor has two
123  * components: the last page of partially allocated sectors and the offset to last sector in this page.
124  * When the sector becomes full, the cursor is incremented. When all page becomes full, the cursor is moved to next
125  * page. */
126  VPID vpid_last_temp_alloc; /* VPID of partial table page last used to allocate a page. */
127  int offset_to_last_temp_alloc; /* Sector offset in partial table last used to allocate a page. */
128 
129  /* Numerable files */
130  /* Numerable files have an additional property compared to regular files. The order of user page allocation is
131  * tracked and the user can get nth page according to this order. To optimize allocations, we keep the VPID of last
132  * page of user page table. Newly allocated page is appended here. */
134 
135  /* cache last file_numerable_find_nth page and index of its entry. used as an optimization for external sort files.
136  * the extensible hash case is not interesting for this optimization (because they are usually small files and because
137  * the access pattern is less predictable.
138  * the usual pattern external sort files is find nth, find nth+1, find nth+2 and so on. so we can cache the page and
139  * index of its first entry from last search to predict where the next file_numerable_find_nth will land.
140  *
141  * how it works:
142  * cache last search location for file_numerable_find_nth by saving user page table page VPID and index of first entry
143  * in page. next search will probably land in the same page (and it will just need to get to the right offset).
144  * if a page is deallocated, the cached location is reset (this is just a safe-guard since external sort does not
145  * deallocate pages currently.
146  * if a page is allocated, since it is appended at the end, will not affect the cached search location. current thread
147  * is actually the only one accessing the file so it can change it safely without promoting to write latch. to avoid
148  * safe-guards, we won't set the page dirty (it is hot anyway and likely to remain in memory).
149  */
152 
153  /* reserved area for future extension */
154  INT32 reserved0;
155  INT32 reserved1;
156  INT32 reserved2;
157  INT32 reserved3;
158 };
159 
160 /* Disk size of file header. */
161 #define FILE_HEADER_ALIGNED_SIZE ((INT16) (DB_ALIGN (sizeof (FILE_HEADER), MAX_ALIGNMENT)))
162 
163 /* File flags. */
164 #define FILE_FLAG_NUMERABLE 0x1 /* Is file numerable */
165 #define FILE_FLAG_TEMPORARY 0x2 /* Is file temporary */
166 #define FILE_FLAG_ENCRYPTED_AES 0x4 /* Is file encrypted using AES */
167 #define FILE_FLAG_ENCRYPTED_ARIA 0x8 /* Is file encrypted using ARIA */
168 
169 #define FILE_FLAG_ENCRYPTED_MASK 0x0000000c /* 0x4 + 0x8 */
170 
171 #define FILE_IS_NUMERABLE(fh) (((fh)->file_flags & FILE_FLAG_NUMERABLE) != 0)
172 #define FILE_IS_TEMPORARY(fh) (((fh)->file_flags & FILE_FLAG_TEMPORARY) != 0)
173 #define FILE_IS_TDE_ENCRYPTED(fh) (((fh)->file_flags & FILE_FLAG_ENCRYPTED_MASK) != 0)
174 
175 #define FILE_CACHE_LAST_FIND_NTH(fh) \
176  (FILE_IS_NUMERABLE (fh) && FILE_IS_TEMPORARY (fh) && (fh)->type == FILE_TEMP)
177 
178 /* Numerable file types. Currently, we used this property for extensible hashes and sort files. */
179 #define FILE_TYPE_CAN_BE_NUMERABLE(ftype) ((ftype) == FILE_EXTENDIBLE_HASH \
180  || (ftype) == FILE_EXTENDIBLE_HASH_DIRECTORY \
181  || (ftype) == FILE_TEMP)
182 #define FILE_TYPE_IS_ALWAYS_TEMP(ftype) ((ftype) == FILE_TEMP \
183  || (ftype) == FILE_QUERY_AREA)
184 #define FILE_TYPE_IS_SOMETIMES_TEMP(ftype) ((ftype) == FILE_EXTENDIBLE_HASH \
185  || (ftype) == FILE_EXTENDIBLE_HASH_DIRECTORY)
186 #define FILE_TYPE_IS_NEVER_TEMP(ftype) (!FILE_TYPE_IS_ALWAYS_TEMP (ftype) && !FILE_TYPE_IS_SOMETIMES_TEMP (ftype))
187 
188 /* Convert VFID to file header page VPID. */
189 #define FILE_GET_HEADER_VPID(vfid, vpid) (vpid)->volid = (vfid)->volid; (vpid)->pageid = (vfid)->fileid
190 
191 /* Get pointer to partial table in file header page */
192 #define FILE_HEADER_GET_PART_FTAB(fh, parttab) \
193  assert ((fh)->offset_to_partial_ftab >= FILE_HEADER_ALIGNED_SIZE && (fh)->offset_to_partial_ftab < DB_PAGESIZE); \
194  (parttab) = (FILE_EXTENSIBLE_DATA *) (((char *) fh) + (fh)->offset_to_partial_ftab)
195 /* Get pointer to full table in file header page */
196 #define FILE_HEADER_GET_FULL_FTAB(fh, fulltab) \
197  assert (!FILE_IS_TEMPORARY (fh)); \
198  assert ((fh)->offset_to_full_ftab>= FILE_HEADER_ALIGNED_SIZE && (fh)->offset_to_full_ftab < DB_PAGESIZE); \
199  (fulltab) = (FILE_EXTENSIBLE_DATA *) (((char *) fh) + (fh)->offset_to_full_ftab)
200 /* Get pointer to user page table in file header page */
201 #define FILE_HEADER_GET_USER_PAGE_FTAB(fh, pagetab) \
202  assert (FILE_IS_NUMERABLE (fh)); \
203  assert ((fh)->offset_to_user_page_ftab >= FILE_HEADER_ALIGNED_SIZE && (fh)->offset_to_user_page_ftab < DB_PAGESIZE); \
204  (pagetab) = (FILE_EXTENSIBLE_DATA *) (((char *) fh) + (fh)->offset_to_user_page_ftab)
205 
206 /************************************************************************/
207 /* File extensible data section */
208 /************************************************************************/
209 
210 /* File extensible data is a generic format to keep theoretically unlimited data in multiple disk pages. Each page is
211  * a component of full data. Each component has a header which keeps a link to next page and useful information about
212  * this component. The header is followed by data.
213  *
214  * The data is considered a set of items. Items have constant size.
215  *
216  * File extensible data is designed to easily access and manipulate data items. It can be used for multiple purposes
217  * (e.g. file tables, file tracker).
218  *
219  * Items in extensible data can be ordered. The user must provide the right compare function. */
220 
221 /* FILE_EXTENSIBLE_DATA -
222  * This structure is actually the beginning of a extensible data component. It is usually accessed as a pointer in page.
223  */
226 {
228  INT16 max_size;
230  INT16 n_items;
231 };
232 /* Disk size for extensible data header */
233 #define FILE_EXTDATA_HEADER_ALIGNED_SIZE (DB_ALIGN (sizeof (FILE_EXTENSIBLE_DATA), MAX_ALIGNMENT))
234 
235 /* FILE_EXTENSIBLE_DATA_SEARCH_CONTEXT -
236  * Helper used for searching an item in extensible data. */
239 {
240  const void *item_to_find; /* Pointer to item to find. */
241  int (*compare_func) (const void *, const void *); /* Compare function used to find the item. */
242  bool found; /* Set to true when item is found. */
243  int position; /* Saves the position of found item in its component */
244 };
245 
246 /* Functions for file_extdata_apply_funcs */
247 typedef int (*FILE_EXTDATA_FUNC) (THREAD_ENTRY * thread_p,
248  const FILE_EXTENSIBLE_DATA * extdata, bool * stop, void *args);
249 typedef int (*FILE_EXTDATA_ITEM_FUNC) (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args);
250 
251 /************************************************************************/
252 /* Partially allocated sectors section */
253 /************************************************************************/
254 
255 /* Partial sector table (full name would be partially allocated sector table, but we will refer to them just by partial
256  * sectors) stores reserved sectors and bitmaps for allocated pages in these sectors. Usually, when all sector pages are
257  * allocated, the sector is removed from partial sector table. This rule does not apply to temporary files, which for
258  * simplicity, only use this partial sector table without moving its content to full table sector.
259  *
260  * Each bit in bitmap represents a page, and a page is considered allocated if its bit is set or free if the bit is not
261  * set.
262  */
263 
264 /* FILE_ALLOC_BITMAP -
265  * Type used to store allocation bitmap for sectors. */
266 typedef UINT64 FILE_ALLOC_BITMAP;
267 #define FILE_FULL_PAGE_BITMAP 0xFFFFFFFFFFFFFFFF /* Full allocation bitmap */
268 #define FILE_EMPTY_PAGE_BITMAP 0x0000000000000000 /* Empty allocation bitmap */
269 
270 #define FILE_ALLOC_BITMAP_NBITS ((int) (sizeof (FILE_ALLOC_BITMAP) * CHAR_BIT))
271 
272 /* FILE_PARTIAL_SECTOR -
273  * Structure used by partially allocated sectors table. Store sector VSID and its allocation bitmap. */
276 {
277  VSID vsid; /* Important - VSID must be first member of FILE_PARTIAL_SECTOR. Sometimes, the
278  * FILE_PARTIAL_SECTOR pointers in file table are reinterpreted as VSID. */
280 };
281 #define FILE_PARTIAL_SECTOR_INITIALIZER { VSID_INITIALIZER, 0 }
282 
283 /************************************************************************/
284 /* Utility structures */
285 /************************************************************************/
286 
287 /* Table space default macro's */
288 #define FILE_TABLESPACE_DEFAULT_RATIO_EXPAND ((float) 0.01) /* 1% of current size */
289 #define FILE_TABLESPACE_DEFAULT_MIN_EXPAND (DISK_SECTOR_NPAGES * DB_PAGESIZE); /* one sector */
290 #define FILE_TABLESPACE_DEFAULT_MAX_EXPAND (DISK_SECTOR_NPAGES * DB_PAGESIZE * 1024); /* 1k sectors */
291 
292 #define FILE_TABLESPACE_FOR_PERM_NPAGES(tabspace, npages) \
293  ((FILE_TABLESPACE *) (tabspace))->initial_size = (INT64) MAX (1, npages) * DB_PAGESIZE; \
294  ((FILE_TABLESPACE *) (tabspace))->expand_ratio = FILE_TABLESPACE_DEFAULT_RATIO_EXPAND; \
295  ((FILE_TABLESPACE *) (tabspace))->expand_min_size = FILE_TABLESPACE_DEFAULT_MIN_EXPAND; \
296  ((FILE_TABLESPACE *) (tabspace))->expand_max_size = FILE_TABLESPACE_DEFAULT_MAX_EXPAND
297 
298 #define FILE_TABLESPACE_FOR_TEMP_NPAGES(tabspace, npages) \
299  ((FILE_TABLESPACE *) (tabspace))->initial_size = (INT64) MAX (1, npages) * DB_PAGESIZE; \
300  ((FILE_TABLESPACE *) (tabspace))->expand_ratio = 0; \
301  ((FILE_TABLESPACE *) (tabspace))->expand_min_size = 0; \
302  ((FILE_TABLESPACE *) (tabspace))->expand_max_size = 0
303 
304 /* FILE_VSID_COLLECTOR -
305  * Collect sector ID's. File destroy uses it. */
308 {
310  int n_vsids;
311 };
312 
313 /* logging */
314 static bool file_Logging = false;
315 
316 #define file_log(func, msg, ...) \
317  if (file_Logging) \
318  _er_log_debug (ARG_FILE_LINE, "FILE " func " " LOG_THREAD_TRAN_MSG ": " msg "\n", \
319  LOG_THREAD_TRAN_ARGS(thread_get_thread_entry_info ()), __VA_ARGS__)
320 
321 #define FILE_PERM_TEMP_STRING(is_temp) ((is_temp) ? "temporary" : "permanent")
322 #define FILE_NUMERABLE_REGULAR_STRING(is_numerable) ((is_numerable) ? "numerable" : "regular")
323 
324 #define FILE_TABLESPACE_MSG \
325  "\ttablespace = { init_size = %lld, expand_ratio = %f, expand_min_size = %d, expand_max_size = %d } \n"
326 #define FILE_TABLESPACE_AS_ARGS(tabspace) \
327  (long long int) (tabspace)->initial_size, (tabspace)->expand_ratio, (tabspace)->expand_min_size, \
328  (tabspace)->expand_max_size
329 
330 #define FILE_HEAD_ALLOC_MSG \
331  "\tfile header: \n" \
332  "\t\tvfid = %d|%d \n" \
333  "\t\t%s \n" \
334  "\t\t%s \n" \
335  "\t\ttde_algorithm: %s \n" \
336  "\t\tpage: total = %d, user = %d, table = %d, free = %d \n" \
337  "\t\tsector: total = %d, partial = %d, full = %d, empty = %d \n"
338 #define FILE_HEAD_ALLOC_AS_ARGS(fhead) \
339  VFID_AS_ARGS (&(fhead)->self), \
340  FILE_PERM_TEMP_STRING (FILE_IS_TEMPORARY (fhead)), \
341  FILE_NUMERABLE_REGULAR_STRING (FILE_IS_NUMERABLE (fhead)), \
342  tde_get_algorithm_name (file_get_tde_algorithm_internal (fhead)), \
343  (fhead)->n_page_total, (fhead)->n_page_user, (fhead)->n_page_ftab, (fhead)->n_page_free, \
344  (fhead)->n_sector_total, (fhead)->n_sector_partial, (fhead)->n_sector_full, (fhead)->n_sector_empty
345 
346 #define FILE_HEAD_FULL_MSG \
347  FILE_HEAD_ALLOC_MSG \
348  "\t\ttime_creation = %lld, type = %s \n" \
349  "\t" FILE_TABLESPACE_MSG \
350  "\t\ttable offsets: partial = %d, full = %d, user page = %d \n" \
351  "\t\tvpid_sticky_first = %d|%d \n" \
352  "\t\tvpid_last_temp_alloc = %d|%d, offset_to_last_temp_alloc=%d \n" \
353  "\t\tvpid_last_user_page_ftab = %d|%d \n" \
354  "\t\tvpid_find_nth_last = %d|%d, first_index_find_nth_last = %d \n"
355 #define FILE_HEAD_FULL_AS_ARGS(fhead) \
356  FILE_HEAD_ALLOC_AS_ARGS (fhead), \
357  (long long int) fhead->time_creation, file_type_to_string ((fhead)->type), \
358  FILE_TABLESPACE_AS_ARGS (&(fhead)->tablespace), \
359  (fhead)->offset_to_partial_ftab, (fhead)->offset_to_full_ftab, (fhead)->offset_to_user_page_ftab, \
360  VPID_AS_ARGS (&(fhead)->vpid_sticky_first), \
361  VPID_AS_ARGS (&(fhead)->vpid_last_temp_alloc), (fhead)->offset_to_last_temp_alloc, \
362  VPID_AS_ARGS (&(fhead)->vpid_last_user_page_ftab), \
363  VPID_AS_ARGS (&(fhead)->vpid_find_nth_last), (fhead)->first_index_find_nth_last
364 
365 #define FILE_EXTDATA_MSG(name) \
366  "\t" name ": { vpid_next = %d|%d, max_size = %d, item_size = %d, n_items = %d } \n"
367 #define FILE_EXTDATA_AS_ARGS(extdata) \
368  VPID_AS_ARGS (&(extdata)->vpid_next), (extdata)->max_size, (extdata)->size_of_item, (extdata)->n_items
369 
370 #define FILE_PARTSECT_MSG(name) \
371  "\t" name ": { vsid = %d|%d, page bitmap = " BIT64_HEXA_PRINT_FORMAT " } \n"
372 #define FILE_PARTSECT_AS_ARGS(ps) VSID_AS_ARGS (&(ps)->vsid), (long long unsigned int) (ps)->page_bitmap
373 
374 #define FILE_ALLOC_TYPE_STRING(alloc_type) \
375  ((alloc_type) == FILE_ALLOC_USER_PAGE ? "alloc user page" : "alloc table page")
376 
377 #define FILE_TEMPCACHE_MSG \
378  "\ttempcache: \n" \
379  "\t\tfile cache: max = %d, numerable = %d, regular = %d, total = %d \n" \
380  "\t\tfree entries: max = %d, count = %d \n"
381 #define FILE_TEMPCACHE_AS_ARGS \
382  file_Tempcache->ncached_max, file_Tempcache->ncached_numerable, file_Tempcache->ncached_not_numerable, \
383  file_Tempcache->ncached_numerable + file_Tempcache->ncached_not_numerable, \
384  file_Tempcache->nfree_entries_max, file_Tempcache->nfree_entries
385 
386 #define FILE_TEMPCACHE_ENTRY_MSG "%p, VFID %d|%d, %s"
387 #define FILE_TEMPCACHE_ENTRY_AS_ARGS(ent) ent, VFID_AS_ARGS (&(ent)->vfid), file_type_to_string ((ent)->ftype)
388 
389 #define FILE_TRACK_ITEM_MSG "VFID %d|%d, %s"
390 #define FILE_TRACK_ITEM_AS_ARGS(item) (item)->volid, (item)->fileid, file_type_to_string ((FILE_TYPE) (item)->type)
391 
392 /************************************************************************/
393 /* File manipulation section */
394 /************************************************************************/
395 
396 /* FILE_ALLOC_TYPE -
397  * The internal workings of file manager may need disk pages to hold the header and data tables. these are considered
398  * file table pages and must also be tracked besides user pages (pages allocated using file_alloc) */
399 typedef enum
400 {
403  FILE_ALLOC_TABLE_PAGE_FULL_SECTOR /* used to allocate a table page necessary for full sectors */
405 
406 #define FILE_RV_DEALLOC_COMPENSATE true
407 #define FILE_RV_DEALLOC_RUN_POSTPONE false
408 
411 {
412  int npages;
413  int nsects;
415 };
416 #define FILE_FTAB_COLLECTOR_INITIALIZER { 0, 0, NULL }
417 
418 /* FILE_MAP_CONTEXT - context variables for file_map_pages function. */
421 {
426 
427  bool stop;
428 
430  void *args;
431 };
432 
433 /* FILE_SET_TDE_ALGORITHM_ARGS - args varaible for file_apply_tde_algorithm() */
436 {
439 };
440 
441 /************************************************************************/
442 /* Numerable files section */
443 /************************************************************************/
444 
445 #define FILE_USER_PAGE_MARK_DELETE_FLAG ((PAGEID) 0x80000000)
446 #define FILE_USER_PAGE_IS_MARKED_DELETED(vpid) ((((VPID *) vpid)->pageid & FILE_USER_PAGE_MARK_DELETE_FLAG) != 0)
447 #define FILE_USER_PAGE_MARK_DELETED(vpid) ((VPID *) vpid)->pageid |= FILE_USER_PAGE_MARK_DELETE_FLAG
448 #define FILE_USER_PAGE_CLEAR_MARK_DELETED(vpid) ((VPID *) vpid)->pageid &= ~FILE_USER_PAGE_MARK_DELETE_FLAG
449 
450 /* FILE_FIND_NTH_CONTEXT -
451  * structure used for finding nth page. */
454 {
456  int nth;
458 };
459 
460 /************************************************************************/
461 /* Temporary files section */
462 /************************************************************************/
463 
464 /************************************************************************/
465 /* Temporary cache section */
466 /************************************************************************/
469 {
472 
474 };
475 
478 {
479  FILE_TEMPCACHE_ENTRY *free_entries; /* preallocated entries free to be use */
482 
483  FILE_TEMPCACHE_ENTRY *cached_not_numerable; /* cached temporary files */
484  FILE_TEMPCACHE_ENTRY *cached_numerable; /* cached temporary numerable files */
488 
489  pthread_mutex_t mutex;
490 #if !defined (NDEBUG)
492 #endif /* !NDEBUG */
493 
494  FILE_TEMPCACHE_ENTRY **tran_files; /* transaction temporary files */
495 
496  /* space info */
498 };
499 
501 
502 /************************************************************************/
503 /* File tracker section */
504 /************************************************************************/
505 
508 
511 {
513  bool dummy[7]; /* dummy fields to 8 bytes */
514 };
515 
518 {
520 
522 };
523 
526 {
527  INT32 fileid; /* 4 bytes */
528  INT16 volid; /* 2 bytes */
529  INT16 type; /* 2 bytes */
531 
532  /* total 16 bytes */
533 };
534 
537 {
538  FILE *fp;
540 };
541 
544 {
546  bool is_undo;
547 };
548 
551 {
554 };
555 
556 typedef int (*FILE_TRACK_ITEM_FUNC) (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA * extdata,
557  int index_item, bool * stop, void *args);
558 
559 /* Since indexes are built with SIX_LOCK, which allows check access an immature index file.
560  * To skip checking an immature index, check it with IX_LOCK which is incompatible with SIX_LOCK.
561  */
562 #define FILE_GET_TRACKER_LOCK_MODE(file_type) (((file_type) == FILE_BTREE) ? IX_LOCK : SCH_S_LOCK)
563 
564 /************************************************************************/
565 /* End of structures, globals and macro's */
566 /************************************************************************/
567 
568 /************************************************************************/
569 /* Declare static functions. */
570 /************************************************************************/
571 
572 /************************************************************************/
573 /* File manager section */
574 /************************************************************************/
575 
576 /************************************************************************/
577 /* File header section. */
578 /************************************************************************/
579 
583 STATIC_INLINE void file_header_alloc (FILE_HEADER * fhead, FILE_ALLOC_TYPE alloc_type, bool was_empty, bool is_full)
585 STATIC_INLINE void file_header_dealloc (FILE_HEADER * fhead, FILE_ALLOC_TYPE alloc_type, bool is_empty, bool was_full)
587 STATIC_INLINE void file_log_fhead_alloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type,
588  bool was_empty, bool is_full) __attribute__ ((ALWAYS_INLINE));
589 STATIC_INLINE void file_log_fhead_dealloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type,
590  bool is_empty, bool was_full) __attribute__ ((ALWAYS_INLINE));
591 STATIC_INLINE void file_header_update_mark_deleted (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, int delta)
593 STATIC_INLINE int file_header_copy (THREAD_ENTRY * thread_p, const VFID * vfid, FILE_HEADER * fhead_copy)
595 STATIC_INLINE void file_header_dump (THREAD_ENTRY * thread_p, const FILE_HEADER * fhead, FILE * fp)
597 STATIC_INLINE void file_header_dump_descriptor (THREAD_ENTRY * thread_p, const FILE_HEADER * fhead, FILE * fp)
599 
600 /************************************************************************/
601 /* File extensible data section */
602 /************************************************************************/
603 
604 STATIC_INLINE void file_extdata_init (INT16 item_size, INT16 max_size,
616  const void *append_data) __attribute__ ((ALWAYS_INLINE));
618  const void *append_data, INT16 count) __attribute__ ((ALWAYS_INLINE));
621  const FILE_EXTENSIBLE_DATA * extdata_dest) __attribute__ ((ALWAYS_INLINE));
622 STATIC_INLINE bool file_extdata_merge_pages (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata_src,
623  const PAGE_PTR page_src, FILE_EXTENSIBLE_DATA * extdata_dest,
624  PAGE_PTR page_dest, int (*compare_func) (const void *, const void *),
625  bool ordered) __attribute__ ((ALWAYS_INLINE));
626 static int file_extdata_find_and_remove_item (THREAD_ENTRY * thread_p, FILE_EXTENSIBLE_DATA * extdata_first,
627  PAGE_PTR page_first, const void *item,
628  int (*compare_func) (const void *, const void *), bool ordered,
629  void *item_pop, VPID * vpid_merged);
633  FILE_EXTENSIBLE_DATA * extdata_dest,
634  int (*compare_func) (const void *, const void *))
636 static void file_extdata_find_ordered (const FILE_EXTENSIBLE_DATA * extdata, const void *item_to_find,
637  int (*compare_func) (const void *, const void *), bool * found, int *position);
639  int position, int count, const void *data) __attribute__ ((ALWAYS_INLINE));
641  int position, int count) __attribute__ ((ALWAYS_INLINE));
642 static int file_extdata_apply_funcs (THREAD_ENTRY * thread_p, FILE_EXTENSIBLE_DATA * extdata_in,
643  FILE_EXTDATA_FUNC f_extdata, void *f_extdata_args, FILE_EXTDATA_ITEM_FUNC f_item,
644  void *f_item_args, bool for_write, FILE_EXTENSIBLE_DATA ** extdata_out,
645  PAGE_PTR * page_out);
646 static int file_extdata_item_func_for_search (THREAD_ENTRY * thread_p,
647  const void *item, int index, bool * stop, void *args);
649  const FILE_EXTENSIBLE_DATA * extdata, bool * stop, void *args);
650 static int file_extdata_search_item (THREAD_ENTRY * thread_p, FILE_EXTENSIBLE_DATA ** extdata,
651  const void *item_to_find,
652  int (*compare_func) (const void *, const void *),
653  bool is_ordered, bool for_write, bool * found, int *position,
654  PAGE_PTR * page_extdata);
655 static int file_extdata_find_not_full (THREAD_ENTRY * thread_p,
656  FILE_EXTENSIBLE_DATA ** extdata, PAGE_PTR * page_out, bool * found);
658  const FILE_EXTENSIBLE_DATA * extdata, PAGE_PTR page, int position,
659  int count, const void *data) __attribute__ ((ALWAYS_INLINE));
661  const FILE_EXTENSIBLE_DATA * extdata, PAGE_PTR page,
662  int position, int count) __attribute__ ((ALWAYS_INLINE));
664  PAGE_PTR page, const VPID * vpid_next) __attribute__ ((ALWAYS_INLINE));
665 STATIC_INLINE void file_extdata_update_item (THREAD_ENTRY * thread_p, PAGE_PTR page_extdata, const void *item_newval,
666  int index_item, FILE_EXTENSIBLE_DATA * extdata)
667  __attribute__ ((ALWAYS_INLINE));
668 static int file_extdata_all_item_count (THREAD_ENTRY * thread_p, FILE_EXTENSIBLE_DATA * extdata, int *count);
669 static int file_extdata_add_item_count (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop,
670  void *args);
671 
672 /************************************************************************/
673 /* Partially allocated sectors section */
674 /************************************************************************/
675 
676 STATIC_INLINE bool file_partsect_is_full (FILE_PARTIAL_SECTOR * partsect) __attribute__ ((ALWAYS_INLINE));
677 STATIC_INLINE bool file_partsect_is_empty (FILE_PARTIAL_SECTOR * partsect) __attribute__ ((ALWAYS_INLINE));
679  int offset) __attribute__ ((ALWAYS_INLINE));
680 STATIC_INLINE void file_partsect_set_bit (FILE_PARTIAL_SECTOR * partsect, int offset) __attribute__ ((ALWAYS_INLINE));
681 STATIC_INLINE void file_partsect_clear_bit (FILE_PARTIAL_SECTOR * partsect, int offset) __attribute__ ((ALWAYS_INLINE));
683  PAGEID pageid) __attribute__ ((ALWAYS_INLINE));
685  VPID * vpid_out, int *offset_out) __attribute__ ((ALWAYS_INLINE));
686 
687 static int file_rv_partsect_update (THREAD_ENTRY * thread_p, LOG_RCV * rcv, bool set);
688 
689 /************************************************************************/
690 /* Utility functions. */
691 /************************************************************************/
692 
693 static int file_compare_vpids (const void *first, const void *second);
694 static int file_compare_vfids (const void *first, const void *second);
695 static int file_compare_track_items (const void *first, const void *second);
696 
697 static void file_print_name_of_class (THREAD_ENTRY * thread_p, FILE * fp, const OID * class_oid_p);
698 
699 /************************************************************************/
700 /* File manipulation section */
701 /************************************************************************/
702 
703 static int file_table_collect_vsid (THREAD_ENTRY * thread_p, const void *item,
704  int index_unused, bool * stop, void *args);
706  FILE_VSID_COLLECTOR * collector_out) __attribute__ ((ALWAYS_INLINE));
707 static int file_perm_expand (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead);
708 static int file_table_move_partial_sectors_to_header (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead,
709  FILE_ALLOC_TYPE alloc_type, VPID * vpid_alloc_out);
710 static int file_table_append_full_sector_page (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, const VPID * vpid_new);
711 static int file_table_add_full_sector (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, const VSID * vsid);
712 STATIC_INLINE int file_table_collect_ftab_pages (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, bool collect_numerable,
713  FILE_FTAB_COLLECTOR * collector_out) __attribute__ ((ALWAYS_INLINE));
714 static int file_extdata_collect_ftab_pages (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop,
715  void *args);
717  __attribute__ ((ALWAYS_INLINE));
718 STATIC_INLINE int file_init_page_type_internal (THREAD_ENTRY * thread_p, PAGE_PTR page, PAGE_TYPE ptype, bool is_temp)
719  __attribute__ ((ALWAYS_INLINE));
720 static int file_perm_alloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type,
721  VPID * vpid_alloc_out);
722 static int file_perm_dealloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, const VPID * vpid_dealloc,
723  FILE_ALLOC_TYPE alloc_type);
724 static int file_rv_dealloc_internal (THREAD_ENTRY * thread_p, LOG_RCV * rcv, bool compensate_or_run_postpone);
725 
726 STATIC_INLINE int file_create_temp_internal (THREAD_ENTRY * thread_p, int npages, FILE_TYPE ftype, bool is_numerable,
727  VFID * vfid_out) __attribute__ ((ALWAYS_INLINE));
728 static int file_sector_map_pages (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args);
729 static DISK_ISVALID file_table_check (THREAD_ENTRY * thread_p, const VFID * vfid, DISK_VOLMAP_CLONE * disk_map_clone);
730 
731 STATIC_INLINE int file_table_dump (THREAD_ENTRY * thread_p, const FILE_HEADER * fhead, FILE * fp)
732  __attribute__ ((ALWAYS_INLINE));
733 static int file_partial_table_extdata_dump (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop,
734  void *args);
735 static int file_partial_table_item_dump (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args);
736 static int file_full_table_extdata_dump (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop,
737  void *args);
738 static int file_full_table_item_dump (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args);
740  bool * stop, void *args);
741 static int file_user_page_table_item_dump (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop,
742  void *args);
743 static int file_sector_map_dealloc (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args);
744 static int file_set_tde_algorithm (THREAD_ENTRY * thread_p, const VFID * vfid, TDE_ALGORITHM tde_algo);
746 static void file_set_tde_algorithm_internal (FILE_HEADER * fhead, TDE_ALGORITHM tde_algo);
747 
748 /************************************************************************/
749 /* Numerable files section. */
750 /************************************************************************/
751 
752 static int file_numerable_add_page (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, const VPID * vpid);
753 static int file_extdata_find_nth_vpid (THREAD_ENTRY * thread_p,
754  const FILE_EXTENSIBLE_DATA * extdata, bool * stop, void *args);
755 static int file_extdata_find_nth_vpid_and_skip_marked (THREAD_ENTRY * thread_p, const void *data, int index,
756  bool * stop, void *args);
757 static int file_table_check_page_is_in_sectors (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop,
758  void *args);
759 
760 /************************************************************************/
761 /* Temporary files section */
762 /************************************************************************/
763 
764 static int file_temp_alloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type,
765  VPID * vpid_alloc_out);
766 STATIC_INLINE int file_temp_set_type (THREAD_ENTRY * thread_p, VFID * vfid,
767  FILE_TYPE ftype) __attribute__ ((ALWAYS_INLINE));
768 static int file_temp_reset_user_pages (THREAD_ENTRY * thread_p, const VFID * vfid);
769 STATIC_INLINE int file_temp_retire_internal (THREAD_ENTRY * thread_p, const VFID * vfid, bool was_preserved)
770  __attribute__ ((ALWAYS_INLINE));
771 
772 /************************************************************************/
773 /* Temporary cache section */
774 /************************************************************************/
775 
776 static int file_tempcache_init (void);
777 static void file_tempcache_final (void);
778 STATIC_INLINE void file_tempcache_lock (void) __attribute__ ((ALWAYS_INLINE));
779 STATIC_INLINE void file_tempcache_unlock (void) __attribute__ ((ALWAYS_INLINE));
780 STATIC_INLINE void file_tempcache_check_lock (void) __attribute__ ((ALWAYS_INLINE));
784 STATIC_INLINE int file_tempcache_get (THREAD_ENTRY * thread_p, FILE_TYPE ftype, bool numerable,
785  FILE_TEMPCACHE_ENTRY ** entry) __attribute__ ((ALWAYS_INLINE));
786 static bool file_tempcache_check_duplicate (THREAD_ENTRY * thread_p, FILE_TEMPCACHE_ENTRY * entry, bool is_numerable);
788  FILE_TEMPCACHE_ENTRY * entry) __attribute__ ((ALWAYS_INLINE));
791  FILE_TEMPCACHE_ENTRY ** entries)
792  __attribute__ ((ALWAYS_INLINE));
794  __attribute__ ((ALWAYS_INLINE));
796  __attribute__ ((ALWAYS_INLINE));
797 STATIC_INLINE void file_tempcache_dump (FILE * fp) __attribute__ ((ALWAYS_INLINE));
798 
799 /************************************************************************/
800 /* File tracker section */
801 /************************************************************************/
802 
803 static int file_tracker_init_page (THREAD_ENTRY * thread_p, PAGE_PTR page, void *args);
804 static int file_tracker_register (THREAD_ENTRY * thread_p, const VFID * vfid, FILE_TYPE ftype,
805  FILE_TRACK_METADATA * metadata);
806 static int file_tracker_register_internal (THREAD_ENTRY * thread_p, PAGE_PTR page_track_head,
807  const FILE_TRACK_ITEM * item);
808 static int file_tracker_unregister (THREAD_ENTRY * thread_p, const VFID * vfid);
810  FILE_TRACK_ITEM_FUNC func, void *args);
811 static int file_tracker_map (THREAD_ENTRY * thread_p, PGBUF_LATCH_MODE latch_mode, FILE_TRACK_ITEM_FUNC func,
812  void *args);
813 static int file_tracker_item_reuse_heap (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA * extdata,
814  int index_item, bool * stop, void *args);
815 static int file_tracker_item_mark_heap_deleted (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item,
816  FILE_EXTENSIBLE_DATA * extdata, int index_item, bool * stop,
817  void *ignore_args);
819  OID * class_oid, bool * stop) __attribute__ ((ALWAYS_INLINE));
820 static int file_tracker_item_dump (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA * extdata,
821  int index_item, bool * stop, void *args);
822 static int file_tracker_item_dump_capacity (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item,
823  FILE_EXTENSIBLE_DATA * extdata, int index_item, bool * stop, void *args);
824 static int file_tracker_item_dump_heap (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA * extdata,
825  int index_item, bool * stop, void *args);
826 static int file_tracker_item_dump_heap_capacity (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item,
827  FILE_EXTENSIBLE_DATA * extdata, int index_item, bool * stop,
828  void *args);
829 static int file_tracker_item_dump_btree_capacity (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item,
830  FILE_EXTENSIBLE_DATA * extdata, int index_item, bool * stop,
831  void *args);
832 #if defined (SA_MODE)
833 static int file_tracker_item_check (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA * extdata,
834  int index_item, bool * stop, void *args);
835 #endif /* SA_MODE */
836 static int file_tracker_item_spacedb (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA * extdata,
837  int index_item, bool * stop, void *args);
838 static int file_tracker_spacedb (THREAD_ENTRY * thread_p, SPACEDB_FILES * spacedb);
839 
840 /************************************************************************/
841 /* End of static functions */
842 /************************************************************************/
843 
844 /************************************************************************/
845 /* Define functions. */
846 /************************************************************************/
847 
848 /************************************************************************/
849 /* File manager section */
850 /************************************************************************/
851 
852 /*
853  * file_manager_init () - initialize file manager
854  */
855 int
856 file_manager_init (void)
857 {
859 
861 
862  return file_tempcache_init ();
863 }
864 
865 /*
866  * file_manager_final () - finalize file manager
867  */
868 void
870 {
872 }
873 
874 /************************************************************************/
875 /* File header section. */
876 /************************************************************************/
877 
878 /*
879  * file_header_init () - initialize file header
880  *
881  * return : void
882  * fhead (out) : output initialized file header
883  */
884 STATIC_INLINE void
886 {
887  VFID_SET_NULL (&fhead->self);
888 
889  fhead->tablespace.initial_size = 0;
890  fhead->tablespace.expand_ratio = 0;
891  fhead->tablespace.expand_min_size = 0;
892  fhead->tablespace.expand_max_size = 0;
893 
894  fhead->time_creation = 0;
895  fhead->type = FILE_UNKNOWN_TYPE;
896  fhead->file_flags = 0;
902  fhead->first_index_find_nth_last = 0;
904 
905  fhead->n_page_total = 0;
906  fhead->n_page_user = 0;
907  fhead->n_page_ftab = 0;
908  fhead->n_page_mark_delete = 0;
909 
910  fhead->n_sector_total = 0;
911  fhead->n_sector_partial = 0;
912  fhead->n_sector_full = 0;
913  fhead->n_sector_empty = 0;
914 
918 
919  fhead->reserved0 = 0;
920  fhead->reserved1 = 0;
921  fhead->reserved2 = 0;
922  fhead->reserved3 = 0;
923 }
924 
925 /*
926  * file_header_sanity_check () - Debug function used to check the sanity of file header before and after certaion file
927  * file operations.
928  *
929  * return : Void.
930  * fhead (in) : File header.
931  */
932 STATIC_INLINE void
934 {
935 #if !defined (NDEBUG)
936  FILE_EXTENSIBLE_DATA *part_table;
937  FILE_EXTENSIBLE_DATA *full_table;
938  FILE_VSID_COLLECTOR collector;
939  int iter_vsid;
940 
942  {
943  /* we cannot guarantee sanity of files headers */
944  return;
945  }
946 
947  assert (!VFID_ISNULL (&fhead->self));
948 
949  assert (fhead->n_page_total > 0);
950  assert (fhead->n_page_user >= 0);
951  assert (fhead->n_page_ftab > 0);
952  assert (fhead->n_page_free >= 0);
953  assert (fhead->n_page_free + fhead->n_page_user + fhead->n_page_ftab == fhead->n_page_total);
954  assert (fhead->n_page_mark_delete >= 0);
955  assert (fhead->n_page_mark_delete <= fhead->n_page_user);
956 
957  assert (fhead->n_sector_total > 0);
958  assert (fhead->n_sector_partial >= 0);
959  assert (fhead->n_sector_empty >= 0);
960  assert (fhead->n_sector_full >= 0);
961  assert (fhead->n_sector_empty <= fhead->n_sector_partial);
962  assert (fhead->n_sector_partial + fhead->n_sector_full == fhead->n_sector_total);
963 
964  if (fhead->n_page_free == 0)
965  {
966  assert (fhead->n_sector_total == fhead->n_sector_full);
967  }
968 
969  // in some scenario with many file manipulation operations, next checks may be too slow. They gradually stack and
970  // waiting times for file headers grow continuously.
971  // skip the check if there are waiters on file header.
972  // don't skip if file logging is activated. it means a bug in file manipulation is investigated and header checks may
973  // be valuable.
975  {
976  return;
977  }
978 
979  er_stack_push ();
980 
981  FILE_HEADER_GET_PART_FTAB (fhead, part_table);
982  if (fhead->n_sector_partial == 0)
983  {
984  assert (FILE_IS_TEMPORARY (fhead)
985  || (file_extdata_is_empty (part_table) && VPID_ISNULL (&part_table->vpid_next)));
986  }
987  else
988  {
989  int part_cnt = 0;
990 
991  assert (!file_extdata_is_empty (part_table) || !VPID_ISNULL (&part_table->vpid_next));
992 
993  if (file_extdata_all_item_count (thread_p, part_table, &part_cnt) != NO_ERROR)
994  {
995  /* thread might be interrupted; give up checking */
996  ASSERT_ERROR ();
997  goto exit;
998  }
999  assert (FILE_IS_TEMPORARY (fhead) || fhead->n_sector_partial == part_cnt);
1000  }
1001 
1002  if (!FILE_IS_TEMPORARY (fhead))
1003  {
1004  FILE_HEADER_GET_FULL_FTAB (fhead, full_table);
1005  if (fhead->n_sector_full == 0)
1006  {
1007  assert (file_extdata_is_empty (full_table) && VPID_ISNULL (&full_table->vpid_next));
1008  }
1009  else
1010  {
1011  int full_cnt = 0;
1012 
1013  assert (!file_extdata_is_empty (full_table) || !VPID_ISNULL (&full_table->vpid_next));
1014 
1015  if (file_extdata_all_item_count (thread_p, full_table, &full_cnt) != NO_ERROR)
1016  {
1017  /* thread might be interrupted; give up checking */
1018  ASSERT_ERROR ();
1019  goto exit;
1020  }
1021  assert (FILE_IS_TEMPORARY (fhead) || fhead->n_sector_full == full_cnt);
1022  }
1023  }
1024 
1025  if (file_table_collect_all_vsids (thread_p, (PAGE_PTR) fhead, &collector) != NO_ERROR)
1026  {
1027  ASSERT_ERROR ();
1028  goto exit;
1029  }
1030 
1031  for (iter_vsid = 0; iter_vsid < collector.n_vsids - 1; iter_vsid++)
1032  {
1033  /* A VSID can't appears twice in tables. */
1034  assert (disk_compare_vsids (&collector.vsids[iter_vsid], &collector.vsids[iter_vsid + 1]) != 0);
1035  }
1036 
1037  if (collector.vsids != NULL)
1038  {
1039  db_private_free (thread_p, collector.vsids);
1040  }
1041 
1042 exit:
1043  /* forget any error of the function */
1044  er_stack_pop ();
1045 #endif /* !NDEBUG */
1046 }
1047 
1048 /*
1049  * file_rv_fhead_set_last_user_page_ftab () - Recovery of file header: set the VPID of last page in user page table.
1050  *
1051  * return : Error code
1052  * thread_p (in) : Thread entry
1053  * rcv (in) : Recovery data
1054  */
1055 int
1057 {
1058  PAGE_PTR page_fhead = rcv->pgptr;
1059  VPID *vpid = (VPID *) rcv->data;
1060  FILE_HEADER *fhead;
1061 
1062  assert (rcv->pgptr != NULL);
1063  assert (rcv->length == sizeof (VPID));
1064 
1065  fhead = (FILE_HEADER *) page_fhead;
1066 
1067  /* the correct VPID is logged. */
1068 
1069  VPID_COPY (&fhead->vpid_last_user_page_ftab, vpid);
1070 
1071  file_log ("file_rv_fhead_set_last_user_page_ftab",
1072  "update vpid_last_user_page_ftab to %d|%d in file %d|%d, "
1073  "header page %d|%d, lsa %lld|%d ", VPID_AS_ARGS (vpid), VFID_AS_ARGS (&fhead->self),
1074  PGBUF_PAGE_STATE_ARGS (page_fhead));
1075 
1076  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
1077  return NO_ERROR;
1078 }
1079 
1080 /*
1081  * file_header_alloc () - Update stats in file header for page allocation.
1082  *
1083  * return : Void
1084  * fhead (in) : File header
1085  * alloc_type (in) : User/table page
1086  * was_empty (in) : True if sector was empty before allocation.
1087  * is_full (in) : True if sector is full after allocation.
1088  */
1089 STATIC_INLINE void
1090 file_header_alloc (FILE_HEADER * fhead, FILE_ALLOC_TYPE alloc_type, bool was_empty, bool is_full)
1091 {
1092  assert (fhead != NULL);
1093  assert (alloc_type == FILE_ALLOC_USER_PAGE || alloc_type == FILE_ALLOC_TABLE_PAGE
1094  || alloc_type == FILE_ALLOC_TABLE_PAGE_FULL_SECTOR);
1095  assert (!was_empty || !is_full);
1096 
1097  fhead->n_page_free--;
1098  if (alloc_type == FILE_ALLOC_USER_PAGE)
1099  {
1100  fhead->n_page_user++;
1101  }
1102  else
1103  {
1104  fhead->n_page_ftab++;
1105  }
1106 
1107  if (was_empty)
1108  {
1109  fhead->n_sector_empty--;
1110  }
1111 
1112  if (is_full)
1113  {
1114  fhead->n_sector_partial--;
1115  fhead->n_sector_full++;
1116  }
1117 }
1118 
1119 /*
1120  * file_header_dealloc () - Update stats in file header for page deallocation.
1121  *
1122  * return : Void
1123  * fhead (in) : File header
1124  * alloc_type (in) : User/table page
1125  * is_empty (in) : True if sector is empty after deallocation.
1126  * was_full (in) : True if sector was full before deallocation.
1127  */
1128 STATIC_INLINE void
1129 file_header_dealloc (FILE_HEADER * fhead, FILE_ALLOC_TYPE alloc_type, bool is_empty, bool was_full)
1130 {
1131  assert (fhead != NULL);
1132  assert (alloc_type == FILE_ALLOC_USER_PAGE || alloc_type == FILE_ALLOC_TABLE_PAGE);
1133  assert (!is_empty || !was_full);
1134 
1135  fhead->n_page_free++;
1136  if (alloc_type == FILE_ALLOC_USER_PAGE)
1137  {
1138  fhead->n_page_user--;
1139  }
1140  else
1141  {
1142  fhead->n_page_ftab--;
1143  }
1144 
1145  if (is_empty)
1146  {
1147  fhead->n_sector_empty++;
1148  }
1149 
1150  if (was_full)
1151  {
1152  fhead->n_sector_partial++;
1153  fhead->n_sector_full--;
1154  }
1155 }
1156 
1157 /*
1158  * file_rv_fhead_alloc () - Recovery for file header when a page is allocated.
1159  *
1160  * return : Error code
1161  * thread_p (in) : Thread entry
1162  * rcv (in) : Recovery data
1163  */
1164 int
1166 {
1167  PAGE_PTR page_fhead = rcv->pgptr;
1168  FILE_HEADER *fhead;
1169  bool is_ftab_page;
1170  bool is_full;
1171  bool was_empty;
1172 
1173  assert (rcv->length == sizeof (bool) * 3);
1174 
1175  is_ftab_page = ((bool *) rcv->data)[0];
1176  was_empty = ((bool *) rcv->data)[1];
1177  is_full = ((bool *) rcv->data)[2];
1178 
1179  fhead = (FILE_HEADER *) page_fhead;
1180 
1181  file_header_alloc (fhead, is_ftab_page ? FILE_ALLOC_TABLE_PAGE : FILE_ALLOC_USER_PAGE, was_empty, is_full);
1182 
1183  file_log ("file_rv_fhead_alloc",
1184  "update header in file %d|%d, header page %d|%d, lsa %lld|%d, "
1185  "after %s, was_empty %s, is_full %s \n" FILE_HEAD_ALLOC_MSG,
1186  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_STATE_ARGS (page_fhead),
1187  FILE_ALLOC_TYPE_STRING (is_ftab_page ? FILE_ALLOC_TABLE_PAGE : FILE_ALLOC_USER_PAGE),
1188  was_empty ? "true" : "false", is_full ? "true" : "false", FILE_HEAD_ALLOC_AS_ARGS (fhead));
1189 
1190  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
1191 
1192  return NO_ERROR;
1193 }
1194 
1195 /*
1196  * file_rv_fhead_dealloc () - Recovery for file header when a page is deallocated.
1197  *
1198  * return : Error code
1199  * thread_p (in) : Thread entry
1200  * rcv (in) : Recovery data
1201  */
1202 int
1204 {
1205  PAGE_PTR page_fhead = rcv->pgptr;
1206  FILE_HEADER *fhead;
1207  bool is_ftab_page;
1208  bool was_full;
1209  bool is_empty;
1210 
1211  assert (rcv->length == sizeof (bool) * 3);
1212 
1213  is_ftab_page = ((bool *) rcv->data)[0];
1214  is_empty = ((bool *) rcv->data)[1];
1215  was_full = ((bool *) rcv->data)[2];
1216 
1217  fhead = (FILE_HEADER *) page_fhead;
1218 
1219  file_header_dealloc (fhead, is_ftab_page ? FILE_ALLOC_TABLE_PAGE : FILE_ALLOC_USER_PAGE, is_empty, was_full);
1220 
1221  file_log ("file_rv_fhead_dealloc",
1222  "update header in file %d|%d, header page %d|%d, lsa %lld|%d, "
1223  "after de%s, is_empty %s, was_full %s \n" FILE_HEAD_ALLOC_MSG,
1224  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_VPID_AS_ARGS (page_fhead),
1225  PGBUF_PAGE_LSA_AS_ARGS (page_fhead),
1226  FILE_ALLOC_TYPE_STRING (is_ftab_page ? FILE_ALLOC_TABLE_PAGE : FILE_ALLOC_USER_PAGE),
1227  is_empty ? "true" : "false", was_full ? "true" : "false", FILE_HEAD_ALLOC_AS_ARGS (fhead));
1228 
1229  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
1230 
1231  return NO_ERROR;
1232 }
1233 
1234 /*
1235  * file_log_fhead_alloc () - Log file header statistics update when a page is allocated.
1236  *
1237  * return : Void.
1238  * thread_p (in) : Thread entry.
1239  * page_fhead (in) : File header page.
1240  * alloc_type (in) : User/table page
1241  * was_empty (in) : True if sector was empty before allocation.
1242  * is_full (in) : True if sector is full after allocation.
1243  */
1244 STATIC_INLINE void
1245 file_log_fhead_alloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, bool was_empty,
1246  bool is_full)
1247 {
1248 #define LOG_BOOL_COUNT 3
1250  bool is_ftab_page = alloc_type != FILE_ALLOC_USER_PAGE;
1251  bool log_bools[3];
1252 
1253  assert (page_fhead != NULL);
1254  assert (alloc_type == FILE_ALLOC_TABLE_PAGE || alloc_type == FILE_ALLOC_USER_PAGE
1255  || alloc_type == FILE_ALLOC_TABLE_PAGE_FULL_SECTOR);
1256  assert (!was_empty || !is_full);
1257 
1258  log_bools[0] = is_ftab_page;
1259  log_bools[1] = was_empty;
1260  log_bools[2] = is_full;
1261 
1262  addr.pgptr = page_fhead;
1263  log_append_undoredo_data (thread_p, RVFL_FHEAD_ALLOC, &addr, sizeof (log_bools), sizeof (log_bools),
1264  log_bools, log_bools);
1265  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
1266 
1267 #undef LOG_BOOL_COUNT
1268 }
1269 
1270 /*
1271  * file_log_fhead_dealloc () - Log file header statistics update when a page is deallocated.
1272  *
1273  * return : Void.
1274  * thread_p (in) : Thread entry.
1275  * page_fhead (in) : File header page.
1276  * alloc_type (in) : User/table page
1277  * is_empty (in) : True if sector is empty after deallocation.
1278  * was_full (in) : True if sector was full before deallocation.
1279  */
1280 STATIC_INLINE void
1281 file_log_fhead_dealloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, bool is_empty,
1282  bool was_full)
1283 {
1284 #define LOG_BOOL_COUNT 3
1286  bool is_ftab_page = (alloc_type == FILE_ALLOC_TABLE_PAGE);
1287  bool log_bools[3];
1288 
1289  assert (page_fhead != NULL);
1290  assert (alloc_type == FILE_ALLOC_TABLE_PAGE || alloc_type == FILE_ALLOC_USER_PAGE);
1291  assert (!is_empty || !was_full);
1292 
1293  log_bools[0] = is_ftab_page;
1294  log_bools[1] = is_empty;
1295  log_bools[2] = was_full;
1296 
1297  addr.pgptr = page_fhead;
1298  log_append_undoredo_data (thread_p, RVFL_FHEAD_DEALLOC, &addr, sizeof (log_bools), sizeof (log_bools),
1299  log_bools, log_bools);
1300  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
1301 
1302 #undef LOG_BOOL_COUNT
1303 }
1304 
1305 /*
1306  * file_header_update_mark_deleted () - Update mark deleted count in file header and log change.
1307  *
1308  * return : Void
1309  * thread_p (in) : Thread entry
1310  * page_fhead (in) : File header page
1311  * delta (in) : Mark deleted delta
1312  */
1313 STATIC_INLINE void
1314 file_header_update_mark_deleted (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, int delta)
1315 {
1316  FILE_HEADER *fhead = (FILE_HEADER *) page_fhead;
1317  int undo_delta = -delta;
1318 
1319  LOG_LSA save_lsa = *pgbuf_get_lsa (page_fhead);
1320 
1321  fhead->n_page_mark_delete += delta;
1322 
1323  if (!FILE_IS_TEMPORARY (fhead))
1324  {
1326  page_fhead, 0, sizeof (undo_delta), sizeof (delta), &undo_delta, &delta);
1327  }
1328  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
1329 
1330  file_log ("file_header_update_mark_deleted",
1331  "updated n_page_mark_delete by %d to %d in file %d|%d, "
1332  "header page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d ", delta,
1333  fhead->n_page_mark_delete, VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_lsa));
1334 }
1335 
1336 /*
1337  * file_rv_header_update_mark_deleted () - Recovery for mark deleted count in file header
1338  *
1339  * return : NO_ERROR
1340  * thread_p (in) : Thread entry
1341  * rcv (in) : Recovery data
1342  */
1343 int
1345 {
1346  int delta = *(int *) rcv->data;
1347  PAGE_PTR page_fhead = rcv->pgptr;
1348  FILE_HEADER *fhead;
1349 
1350  assert (page_fhead != NULL);
1351  assert (rcv->length == sizeof (int));
1352 
1353  fhead = (FILE_HEADER *) page_fhead;
1354  fhead->n_page_mark_delete += delta;
1355  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
1356 
1357  file_log ("file_rv_header_update_mark_deleted",
1358  "modified n_page_mark_delete by %d to %d in file %d|%d, "
1359  "header page %d|%d, lsa %lld|%d", delta,
1360  fhead->n_page_mark_delete, VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_STATE_ARGS (page_fhead));
1361 
1362  return NO_ERROR;
1363 }
1364 
1365 /*
1366  * file_header_copy () - get a file header copy
1367  *
1368  * return : ERROR_CODE
1369  * thread_p (in) : thread entry
1370  * vfid (in) : file identifier
1371  * fhead_copy (out) : file header copy
1372  */
1373 STATIC_INLINE int
1374 file_header_copy (THREAD_ENTRY * thread_p, const VFID * vfid, FILE_HEADER * fhead_copy)
1375 {
1376  VPID vpid_fhead;
1377  PAGE_PTR page_fhead = NULL;
1378  FILE_HEADER *fhead = NULL;
1379  int error_code = NO_ERROR;
1380 
1381  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
1382  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
1383  if (page_fhead == NULL)
1384  {
1385  ASSERT_ERROR_AND_SET (error_code);
1386  return error_code;
1387  }
1388  fhead = (FILE_HEADER *) page_fhead;
1389  file_header_sanity_check (thread_p, fhead);
1390 
1391  *fhead_copy = *fhead;
1392 
1393  pgbuf_unfix (thread_p, page_fhead);
1394  return NO_ERROR;
1395 }
1396 
1397 /*
1398  * file_header_dump () - dump file header to file
1399  *
1400  * return : void
1401  * thread_p (in) : thread entry
1402  * fhead (in) : file header
1403  * fp (in) : output file
1404  */
1405 STATIC_INLINE void
1406 file_header_dump (THREAD_ENTRY * thread_p, const FILE_HEADER * fhead, FILE * fp)
1407 {
1408  fprintf (fp, FILE_HEAD_FULL_MSG, FILE_HEAD_FULL_AS_ARGS (fhead));
1409  file_header_dump_descriptor (thread_p, fhead, fp);
1410 }
1411 
1412 /*
1413  * file_header_dump_descriptor () - dump descriptor in file header
1414  *
1415  * return : void
1416  * thread_p (in) : thread entry
1417  * fhead (in) : file header
1418  * fp (in) : output file
1419  */
1420 STATIC_INLINE void
1421 file_header_dump_descriptor (THREAD_ENTRY * thread_p, const FILE_HEADER * fhead, FILE * fp)
1422 {
1423  switch (fhead->type)
1424  {
1425  case FILE_HEAP:
1426  case FILE_HEAP_REUSE_SLOTS:
1427  file_print_name_of_class (thread_p, fp, &fhead->descriptor.heap.class_oid);
1428  fprintf (fp, "\n");
1429  break;
1430 
1432  fprintf (fp, "Overflow for HFID: %10d|%5d|%10d\n", HFID_AS_ARGS (&fhead->descriptor.heap_overflow.hfid));
1433  break;
1434 
1435  case FILE_BTREE:
1436  {
1437  BTID btid;
1438  char *index_name = NULL;
1439  btid.vfid = fhead->self;
1440  btid.root_pageid = fhead->vpid_sticky_first.pageid;
1441 
1442  if (heap_get_indexinfo_of_btid (thread_p, &fhead->descriptor.btree.class_oid, &btid, NULL, NULL, NULL, NULL,
1443  &index_name, NULL) == NO_ERROR)
1444  {
1445  file_print_name_of_class (thread_p, fp, &fhead->descriptor.btree.class_oid);
1446  fprintf (fp, ", %s, ATTRID: %5d \n", index_name != NULL ? index_name : "*UNKNOWN-INDEX*",
1447  fhead->descriptor.btree.attr_id);
1448  }
1449  }
1450  break;
1451 
1453  fprintf (fp, "Overflow keys for BTID: %10d|%5d|%10d\n",
1455  break;
1456 
1457  case FILE_EXTENDIBLE_HASH:
1459  file_print_name_of_class (thread_p, fp, &fhead->descriptor.ehash.class_oid);
1460  fprintf (fp, ", ATTRID: %5d \n", fhead->descriptor.ehash.attr_id);
1461  break;
1462 
1463  case FILE_TRACKER:
1464  case FILE_CATALOG:
1465  case FILE_QUERY_AREA:
1466  case FILE_TEMP:
1467  case FILE_UNKNOWN_TYPE:
1468  case FILE_DROPPED_FILES:
1469  case FILE_VACUUM_DATA:
1470  default:
1471  break;
1472  }
1473 }
1474 
1475 /************************************************************************/
1476 /* File extensible data section. */
1477 /************************************************************************/
1478 
1479 /*
1480  * file_extdata_init () - Initialize extensible data component for the first time.
1481  *
1482  * return : Void.
1483  * item_size (in) : Size of an item.
1484  * max_size (in) : Desired maximum size for component.
1485  * extdata (out) : Output initialized extensible data.
1486  */
1487 STATIC_INLINE void
1488 file_extdata_init (INT16 item_size, INT16 max_size, FILE_EXTENSIBLE_DATA * extdata)
1489 {
1490  assert (extdata != NULL);
1491  assert (item_size > 0);
1492  assert (max_size > 0);
1493 
1494  VPID_SET_NULL (&extdata->vpid_next);
1495  extdata->size_of_item = item_size;
1496  extdata->n_items = 0;
1497 
1498  /* Align to size of item */
1499  extdata->max_size = DB_ALIGN_BELOW (max_size - FILE_EXTDATA_HEADER_ALIGNED_SIZE, extdata->size_of_item);
1500  if ((INT16) DB_ALIGN (extdata->max_size, MAX_ALIGNMENT) != extdata->max_size)
1501  {
1502  /* We need max alignment */
1503  extdata->max_size = DB_ALIGN (extdata->max_size - extdata->size_of_item, MAX_ALIGNMENT);
1504  }
1505  /* Safe guard: we should fit at least one item. */
1506  assert (extdata->max_size >= extdata->size_of_item);
1507 }
1508 
1509 /*
1510  * file_extdata_max_size () - Get maximum size of this extensible data including header.
1511  *
1512  * return : Maximum size of extensible data.
1513  * extdata (in) : Extensible data.
1514  */
1515 STATIC_INLINE int
1517 {
1518  return FILE_EXTDATA_HEADER_ALIGNED_SIZE + extdata->max_size;
1519 }
1520 
1521 /*
1522  * file_extdata_size () - Get current size of this extensible data including header.
1523  *
1524  * return : Current size of extensible data.
1525  * extdata (in) : Extensible data.
1526  */
1527 STATIC_INLINE int
1529 {
1530  return FILE_EXTDATA_HEADER_ALIGNED_SIZE + extdata->n_items * extdata->size_of_item;
1531 }
1532 
1533 /*
1534  * file_extdata_start () - Get pointer to first item in extensible data.
1535  *
1536  * return : Pointer to first item.
1537  * extdata (in) : Extensible data.
1538  */
1539 STATIC_INLINE void *
1541 {
1542  return ((char *) extdata) + FILE_EXTDATA_HEADER_ALIGNED_SIZE;
1543 }
1544 
1545 /*
1546  * file_extdata_end () - Get pointer to the end of extensible data (after last item).
1547  *
1548  * return : Pointer to end of extensible data.
1549  * extdata (in) : Extensible data.
1550  */
1551 STATIC_INLINE void *
1553 {
1554  return ((char *) extdata) + file_extdata_size (extdata);
1555 }
1556 
1557 /*
1558  * file_extdata_is_full () - Is this extensible data full (not enough room foradditional item).
1559  *
1560  * return : True if full, false otherwise.
1561  * extdata (in) : Extensible data.
1562  */
1563 STATIC_INLINE bool
1565 {
1566  assert (extdata->n_items * extdata->size_of_item <= extdata->max_size);
1567  return (extdata->n_items + 1) * extdata->size_of_item > extdata->max_size;
1568 }
1569 
1570 /*
1571  * file_extdata_is_empty () - Is this extensible data empty?
1572  *
1573  * return : True if empty, false otherwise.
1574  * extdata (in) : Extensible data.
1575  */
1576 STATIC_INLINE bool
1578 {
1579  assert (extdata->n_items >= 0);
1580  return (extdata->n_items <= 0);
1581 }
1582 
1583 /*
1584  * file_extdata_item_count () - Get the item count in this extensible data.
1585  *
1586  * return : Item count.
1587  * extdata (in) : Extensible data.
1588  */
1589 STATIC_INLINE INT16
1591 {
1592  return extdata->n_items;
1593 }
1594 
1595 /*
1596  * file_extdata_remaining_capacity () - Get the remaining capacity (in number of items) of this extensible data.
1597  *
1598  * return : Remaining capacity.
1599  * extdata (in) : Extensible data.
1600  */
1601 STATIC_INLINE INT16
1603 {
1604  return extdata->max_size / extdata->size_of_item - extdata->n_items;
1605 }
1606 
1607 /*
1608  * file_extdata_append () - Append an item to extensible data. Caller should have checked there is enough room.
1609  *
1610  * return : Void.
1611  * extdata (in) : Extensible data.
1612  * append_item (in) : Item to append.
1613  */
1614 STATIC_INLINE void
1615 file_extdata_append (FILE_EXTENSIBLE_DATA * extdata, const void *append_item)
1616 {
1617  assert (!file_extdata_is_full (extdata));
1618 
1619  memcpy (file_extdata_end (extdata), append_item, extdata->size_of_item);
1620  extdata->n_items++;
1621 }
1622 
1623 /*
1624  * file_extdata_append_array () - Append an array of items to extensible data. Caller should have checked there is
1625  * enough room.
1626  *
1627  * return : Void.
1628  * extdata (in) : Extensible data.
1629  * append_items (in) : Item array.
1630  * count (in) : Item count.
1631  */
1632 STATIC_INLINE void
1633 file_extdata_append_array (FILE_EXTENSIBLE_DATA * extdata, const void *append_items, INT16 count)
1634 {
1635  assert (file_extdata_remaining_capacity (extdata) >= count);
1636 
1637  memcpy (file_extdata_end (extdata), append_items, extdata->size_of_item * count);
1638  extdata->n_items += count;
1639 }
1640 
1641 /*
1642  * file_extdata_at () - Pointer to item at given index.
1643  *
1644  * return : Pointer to item.
1645  * extdata (in) : Extensible data.
1646  * index (in) : Item index.
1647  */
1648 STATIC_INLINE void *
1649 file_extdata_at (const FILE_EXTENSIBLE_DATA * extdata, int index)
1650 {
1651  assert (index >= 0 && index <= extdata->n_items);
1652  return (char *) file_extdata_start (extdata) + extdata->size_of_item * index;
1653 }
1654 
1655 /*
1656  * file_extdata_can_merge () - Check if source extensible data component can be merged into destination extensible data.
1657  *
1658  * return : True if destination extensible data remaining capacity can cover all items in source extensible
1659  * data. False otherwise.
1660  * extdata_src (in) : Source extensible data.
1661  * extdata_dest (in) : Destination extensible data.
1662  */
1663 STATIC_INLINE bool
1664 file_extdata_can_merge (const FILE_EXTENSIBLE_DATA * extdata_src, const FILE_EXTENSIBLE_DATA * extdata_dest)
1665 {
1666  return file_extdata_remaining_capacity (extdata_dest) >= extdata_src->n_items;
1667 }
1668 
1669 /*
1670  * file_extdata_merge_unordered () - Append source extensible data to destination extensible data.
1671  *
1672  * return : Void.
1673  * extdata_src (in) : Source extensible data.
1674  * extdata_dest (in/out) : Destination extensible data.
1675  */
1676 STATIC_INLINE void
1678 {
1679  file_extdata_append_array (extdata_dest, file_extdata_start (extdata_src), file_extdata_item_count (extdata_src));
1680 }
1681 
1682 /*
1683  * file_extdata_merge_ordered () - Merge source extensible data into destination extensible data and keep items ordered.
1684  *
1685  * return : Void.
1686  * extdata_src (in) : Source extensible data.
1687  * extdata_dest (in/out) : Destination extensible data.
1688  * compare_func (in) : Compare function (to order items).
1689  */
1690 STATIC_INLINE void
1692  int (*compare_func) (const void *, const void *))
1693 {
1694  char *dest_ptr;
1695  char *dest_end_ptr;
1696  const char *src_ptr;
1697  const char *src_end_ptr;
1698  const char *src_new_ptr;
1699  int memsize = 0;
1700 
1701 #if !defined (NDEBUG)
1702  char *debug_dest_end_ptr =
1703  (char *) file_extdata_end (extdata_dest) + extdata_src->n_items * extdata_src->size_of_item;
1704 #endif /* !NDEBUG */
1705 
1706  /* safe guard: destination has enough capacity to include all source items. */
1707  assert (file_extdata_remaining_capacity (extdata_dest) >= file_extdata_item_count (extdata_src));
1708 
1709  src_ptr = (const char *) file_extdata_start (extdata_src);
1710  src_end_ptr = (const char *) file_extdata_end (extdata_src);
1711 
1712  dest_ptr = (char *) file_extdata_start (extdata_dest);
1713  dest_end_ptr = (char *) file_extdata_end (extdata_dest);
1714 
1715  /* advance source and destination pointers based on item order. Stop when end of destination is reached. */
1716  while (dest_ptr < dest_end_ptr)
1717  {
1718  /* collect all items from source that are smaller than current destination item. */
1719  for (src_new_ptr = src_ptr; src_new_ptr < src_end_ptr; src_new_ptr += extdata_src->size_of_item)
1720  {
1721  assert (compare_func (src_new_ptr, dest_ptr) != 0);
1722  if (compare_func (src_new_ptr, dest_ptr) > 0)
1723  {
1724  break;
1725  }
1726  }
1727  if (src_new_ptr > src_ptr)
1728  {
1729  /* move to dest_ptr */
1730  memsize = (int) (src_new_ptr - src_ptr);
1731  /* make room for new data */
1732  memmove (dest_ptr + memsize, dest_ptr, dest_end_ptr - dest_ptr);
1733  memcpy (dest_ptr, src_ptr, memsize);
1734 
1735  dest_ptr += memsize;
1736  dest_end_ptr += memsize;
1737 
1738  src_ptr = src_new_ptr;
1739 
1740  assert (dest_end_ptr <= debug_dest_end_ptr);
1741  }
1742  if (src_ptr >= src_end_ptr)
1743  {
1744  /* source extensible data was consumed. */
1745  assert (src_ptr == src_end_ptr);
1746  break;
1747  }
1748  /* skip all items from destination smaller than current source item */
1749  for (; dest_ptr < dest_end_ptr; dest_ptr += extdata_dest->size_of_item)
1750  {
1751  assert (compare_func (src_ptr, dest_ptr) != 0);
1752  if (compare_func (src_ptr, dest_ptr) <= 0)
1753  {
1754  break;
1755  }
1756  }
1757  }
1758 
1759  if (src_ptr < src_end_ptr)
1760  {
1761  /* end of destination reached. append remaining source items into destination. */
1762  assert (dest_ptr == dest_end_ptr);
1763  memcpy (dest_end_ptr, src_ptr, src_end_ptr - src_ptr);
1764  assert (dest_end_ptr + (src_end_ptr - src_ptr) == debug_dest_end_ptr);
1765  }
1766  else
1767  {
1768  /* all source items were moved to destination */
1769  assert (debug_dest_end_ptr == dest_end_ptr);
1770  }
1771 
1772  extdata_dest->n_items += extdata_src->n_items;
1773  assert (debug_dest_end_ptr == file_extdata_end (extdata_dest));
1774 }
1775 
1776 /*
1777  * file_extdata_find_ordered () - Find position for given item. If item does not exist, return the position of first
1778  * bigger item.
1779  *
1780  * return : Void.
1781  * extdata (in) : Extensible data.
1782  * item_to_find (in) : Pointer to item to find.
1783  * compare_func (in) : Compare function used for binary search.
1784  * found (out) : Output true if item was found, false otherwise.
1785  * position (out) : Output the right position of item (found or not found).
1786  */
1787 static void
1788 file_extdata_find_ordered (const FILE_EXTENSIBLE_DATA * extdata, const void *item_to_find,
1789  int (*compare_func) (const void *, const void *), bool * found, int *position)
1790 {
1791  assert (found != NULL);
1792  assert (position != NULL);
1793 
1794  *position = util_bsearch (item_to_find, file_extdata_start (extdata), file_extdata_item_count (extdata),
1795  extdata->size_of_item, compare_func, found);
1796 }
1797 
1798 /*
1799  * file_extdata_insert_at () - Insert items at given position in extensible data.
1800  *
1801  * return : Void.
1802  * extdata (in) : Extensible data.
1803  * position (in) : Position to insert items.
1804  * count (in) : Item count.
1805  * data (in) : Items to insert.
1806  */
1807 STATIC_INLINE void
1808 file_extdata_insert_at (FILE_EXTENSIBLE_DATA * extdata, int position, int count, const void *data)
1809 {
1810  char *copy_at;
1811  int memmove_size;
1812 
1813  assert (extdata != NULL);
1814  assert (!file_extdata_is_full (extdata));
1815  assert (data != NULL);
1816  assert (position >= 0 && position <= file_extdata_item_count (extdata));
1817 
1818  /* move current items at desired position to the right. */
1819  memmove_size = (extdata->n_items - position) * extdata->size_of_item;
1820  copy_at = (char *) file_extdata_at (extdata, position);
1821  if (memmove_size > 0)
1822  {
1823  memmove (copy_at + extdata->size_of_item * count, copy_at, memmove_size);
1824  }
1825 
1826  /* copy new items at position */
1827  memcpy (copy_at, data, extdata->size_of_item * count);
1828 
1829  /* update item count */
1830  extdata->n_items += count;
1831 }
1832 
1833 /*
1834  * file_extdata_remove_at () - Remove items from give position in extensible data.
1835  *
1836  * return : Void.
1837  * extdata (in) : Extensible data.
1838  * position (in) : Position where items must be removed.
1839  * count (in) : Item count.
1840  */
1841 STATIC_INLINE void
1842 file_extdata_remove_at (FILE_EXTENSIBLE_DATA * extdata, int position, int count)
1843 {
1844  char *remove_at;
1845  int memmove_size;
1846 
1847  if (position < 0 || position >= extdata->n_items)
1848  {
1849  /* bad index. give up */
1850  assert_release (false);
1851  return;
1852  }
1853 
1854  /* remove items */
1855  remove_at = (char *) file_extdata_at (extdata, position);
1856  memmove_size = (extdata->n_items - count - position) * extdata->size_of_item;
1857  if (memmove_size > 0)
1858  {
1859  memmove (remove_at, remove_at + extdata->size_of_item * count, memmove_size);
1860  }
1861 
1862  /* update item count */
1863  extdata->n_items -= count;
1864 }
1865 
1866 /*
1867  * file_extdata_apply_funcs () - Process extensible data components and apply functions to each component and/or to each
1868  * item.
1869  *
1870  * return : Error code.
1871  * thread_p (in) : Thread entry.
1872  * extdata_in (in) : First extensible data component.
1873  * f_extdata (in) : Function to apply for each extensible data component (can be NULL).
1874  * f_extdata_args (in/out) : Argument for component function.
1875  * f_item (in) : Function to apply for each item (can be NULL).
1876  * f_item_args (in/out) : Argument for item function.
1877  * for_write (in) : Should page be fixed for write?
1878  * extdata_out (out) : Output current extensible data component if processing is stopped.
1879  * page_out (out) : Output page of current extensible data component if processing is stopped.
1880  */
1881 static int
1883  void *f_extdata_args, FILE_EXTDATA_ITEM_FUNC f_item, void *f_item_args,
1884  bool for_write, FILE_EXTENSIBLE_DATA ** extdata_out, PAGE_PTR * page_out)
1885 {
1886  int i;
1887  bool stop = false; /* forces to stop processing extensible data */
1888  PAGE_PTR page_extdata = NULL; /* extensible data page */
1889  PGBUF_LATCH_MODE latch_mode = for_write ? PGBUF_LATCH_WRITE : PGBUF_LATCH_READ;
1890  int error_code = NO_ERROR;
1891  VPID vpid_next = VPID_INITIALIZER;
1892 
1893  if (page_out != NULL)
1894  {
1895  *page_out = NULL; /* make it sure for an error */
1896  }
1897 
1898  while (true)
1899  {
1900  /* catch infinite loop, if any */
1901  assert (page_extdata == NULL || !VPID_EQ (pgbuf_get_vpid_ptr (page_extdata), &extdata_in->vpid_next));
1902  if (f_extdata != NULL)
1903  {
1904  /* apply f_extdata */
1905  error_code = f_extdata (thread_p, extdata_in, &stop, f_extdata_args);
1906  if (error_code != NO_ERROR)
1907  {
1908  ASSERT_ERROR ();
1909  goto exit;
1910  }
1911  if (stop)
1912  {
1913  /* stop processing */
1914  goto exit;
1915  }
1916  }
1917 
1918  if (f_item != NULL)
1919  {
1920  /* iterate through all items in current page. */
1921  for (i = 0; i < file_extdata_item_count (extdata_in); i++)
1922  {
1923  /* apply f_item */
1924  error_code = f_item (thread_p, file_extdata_at (extdata_in, i), i, &stop, f_item_args);
1925  if (error_code != NO_ERROR)
1926  {
1927  ASSERT_ERROR ();
1928  goto exit;
1929  }
1930  if (stop)
1931  {
1932  goto exit;
1933  }
1934  }
1935  }
1936 
1937  if (VPID_ISNULL (&extdata_in->vpid_next))
1938  {
1939  /* end of extensible data. */
1940  break;
1941  }
1942  vpid_next = extdata_in->vpid_next;
1943 
1944  /* advance to next page */
1945  if (page_extdata != NULL)
1946  {
1947  pgbuf_unfix_and_init (thread_p, page_extdata);
1948  }
1949  page_extdata = pgbuf_fix (thread_p, &vpid_next, OLD_PAGE, latch_mode, PGBUF_UNCONDITIONAL_LATCH);
1950  if (page_extdata == NULL)
1951  {
1952  ASSERT_ERROR_AND_SET (error_code);
1953  goto exit;
1954  }
1955  /* get component in next page */
1956  extdata_in = (FILE_EXTENSIBLE_DATA *) page_extdata;
1957  }
1958 
1959 exit:
1960  if (stop && page_out != NULL)
1961  {
1962  /* output current page */
1963  *page_out = page_extdata;
1964  }
1965  else if (page_extdata != NULL)
1966  {
1967  /* unfix current page */
1968  pgbuf_unfix (thread_p, page_extdata);
1969  }
1970 
1971  if (stop && extdata_out != NULL)
1972  {
1973  /* output current extensible data component */
1974  *extdata_out = extdata_in;
1975  }
1976 
1977  return error_code;
1978 }
1979 
1980 /*
1981  * file_extdata_func_for_search_ordered () - Function callable by file_extdata_apply_funcs; binary search for an item
1982  * in ordered extensible data.
1983  *
1984  * return : NO_ERROR.
1985  * thread_p (in) : Thread entry.
1986  * extdata (in) : Extensible data.
1987  * stop (out) : Output true when item is found and search can be stopped.
1988  * args (in/out) : Search context.
1989  */
1990 static int
1992  void *args)
1993 {
1995 
1996  assert (search_context != NULL);
1997 
1998  file_extdata_find_ordered (extdata, search_context->item_to_find, search_context->compare_func,
1999  &search_context->found, &search_context->position);
2000  if (search_context->found)
2001  {
2002  *stop = true;
2003  }
2004 
2005  return NO_ERROR;
2006 }
2007 
2008 /*
2009  * file_extdata_item_func_for_search () - Function callable by file_extdata_apply_funcs; searches item by comparing
2010  * extensible data item to the item in search context.
2011  *
2012  * return : NO_ERROR.
2013  * thread_p (in) : Thread entry.
2014  * item (in) : Item in extensible data.
2015  * index (in) : Index of item in extensible data.
2016  * stop (out) : Output true when item is found and search can be stopped.
2017  * args (in/out) : Search context.
2018  */
2019 static int
2020 file_extdata_item_func_for_search (THREAD_ENTRY * thread_p, const void *item, int index, bool * stop, void *args)
2021 {
2023 
2024  if (search_context->compare_func (search_context->item_to_find, item) == 0)
2025  {
2026  /* Found */
2027  search_context->found = true;
2028  search_context->position = index;
2029  *stop = true;
2030  }
2031  return NO_ERROR;
2032 }
2033 
2034 /*
2035  * file_extdata_search_item () - Search for item in extensible data.
2036  *
2037  * return : Error code.
2038  * thread_p (in) : Thread entry.
2039  * extdata (in/out) : Extensible data. First component as input, component where item was found as output.
2040  * item_to_find (in) : Searched item.
2041  * compare_func (in) : Compare function used to find item.
2042  * is_ordered (in) : True if items in extensible are ordered and can be searched using binary search. False otherwise
2043  * for_write (in) : Should page be fixed for write?
2044  * found (out) : Output true if item is found in extensible data, false otherwise.
2045  * position (out) : Output the position of found item (if found) in its extensible data component.
2046  * page_extdata (out) : Output page of extensible data component where item is found (if found).
2047  */
2048 static int
2049 file_extdata_search_item (THREAD_ENTRY * thread_p, FILE_EXTENSIBLE_DATA ** extdata, const void *item_to_find,
2050  int (*compare_func) (const void *, const void *),
2051  bool is_ordered, bool for_write, bool * found, int *position, PAGE_PTR * page_extdata)
2052 {
2053  FILE_EXTENSIBLE_DATA_SEARCH_CONTEXT search_context;
2054  FILE_EXTENSIBLE_DATA *extdata_in = *extdata;
2055  int error_code = NO_ERROR;
2056 
2057  search_context.item_to_find = item_to_find;
2058  search_context.compare_func = compare_func;
2059  search_context.found = false;
2060  search_context.position = -1;
2061 
2062  if (is_ordered)
2063  {
2064  error_code = file_extdata_apply_funcs (thread_p, extdata_in, file_extdata_func_for_search_ordered,
2065  &search_context, NULL, NULL, for_write, extdata, page_extdata);
2066  if (error_code != NO_ERROR)
2067  {
2068  ASSERT_ERROR ();
2069  assert (*page_extdata == NULL);
2070  return error_code;
2071  }
2072  }
2073  else
2074  {
2075  error_code = file_extdata_apply_funcs (thread_p, extdata_in, NULL, NULL, file_extdata_item_func_for_search,
2076  &search_context, for_write, extdata, page_extdata);
2077  if (error_code != NO_ERROR)
2078  {
2079  ASSERT_ERROR ();
2080  assert (*page_extdata == NULL);
2081  return error_code;
2082  }
2083  }
2084 
2085  if (found != NULL)
2086  {
2087  *found = search_context.found;
2088  }
2089 
2090  if (position != NULL)
2091  {
2092  *position = search_context.position;
2093  }
2094 
2095  return NO_ERROR;
2096 }
2097 
2098 /*
2099  * file_extdata_find_not_full () - Find an extensible data component that is not full.
2100  *
2101  * return : Error code.
2102  * thread_p (in) : Thread entry.
2103  * extdata (in/out) : Extensible data. First component as input, component where free space is found as output.
2104  * page_out (out) : Output page of component with free space.
2105  * found (out) : Output true if a component with free space is found.
2106  */
2107 static int
2108 file_extdata_find_not_full (THREAD_ENTRY * thread_p, FILE_EXTENSIBLE_DATA ** extdata, PAGE_PTR * page_out, bool * found)
2109 {
2110  VPID vpid_next;
2111  int error_code = NO_ERROR;
2112 
2113  assert (extdata != NULL && *extdata != NULL);
2114  assert (page_out != NULL);
2115  assert (found != NULL);
2116 
2117  /* how it works:
2118  * we are looking for the first extensible data component that still has space for one additional item. the extensible
2119  * data and page where the space is found is then output.
2120  *
2121  * note: the input page is usually NULL. the input extensible data usually belongs to file header. this would unfix
2122  * page_out when it advances to next page and we don't want to unfix header page.
2123  * note: if all extensible data components are full, the last extensible data and page are output. the caller can
2124  * then use them to append a new page and a new extensible data component.
2125  */
2126 
2127  *found = false;
2128 
2129  while (file_extdata_is_full (*extdata))
2130  {
2131  VPID_COPY (&vpid_next, &(*extdata)->vpid_next);
2132  if (VPID_ISNULL (&vpid_next))
2133  {
2134  /* Not found. */
2135  return NO_ERROR;
2136  }
2137 
2138  /* Move to next page */
2139  if (*page_out != NULL)
2140  {
2141  pgbuf_unfix_and_init (thread_p, *page_out);
2142  }
2143 
2144  *page_out = pgbuf_fix (thread_p, &vpid_next, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
2145  if (*page_out == NULL)
2146  {
2147  ASSERT_ERROR_AND_SET (error_code);
2148  return error_code;
2149  }
2150 
2151  *extdata = (FILE_EXTENSIBLE_DATA *) (*page_out);
2152  }
2153 
2154  /* Found not full */
2155  *found = true;
2156  return NO_ERROR;
2157 }
2158 
2159 /*
2160  * file_rv_extdata_set_next () - Recovery function to set extensible data next page.
2161  *
2162  * return : NO_ERROR.
2163  * thread_p (in) : Thread entry.
2164  * rcv (in) : Recovery data.
2165  */
2166 int
2168 {
2169  PAGE_PTR page_ftab = rcv->pgptr;
2170  VPID *vpid_next = (VPID *) rcv->data;
2171  FILE_EXTENSIBLE_DATA *extdata = NULL;
2172 
2173  assert (page_ftab != NULL);
2174  assert (rcv->length == sizeof (VPID));
2175  assert (rcv->offset >= 0 && rcv->offset < DB_PAGESIZE);
2176 
2177  extdata = (FILE_EXTENSIBLE_DATA *) (page_ftab + rcv->offset);
2178  VPID_COPY (&extdata->vpid_next, vpid_next);
2179 
2180  file_log ("file_rv_extdata_set_next",
2181  "page %d|%d, lsa %lld|%d, changed extdata link \n"
2182  FILE_EXTDATA_MSG ("extdata after"), PGBUF_PAGE_STATE_ARGS (page_ftab), FILE_EXTDATA_AS_ARGS (extdata));
2183 
2184  pgbuf_set_dirty (thread_p, page_ftab, DONT_FREE);
2185  return NO_ERROR;
2186 }
2187 
2188 /*
2189  * file_rv_dump_extdata_set_next () - Dump VPID for recovery of extensible data next page.
2190  *
2191  * return : Void.
2192  * fp (in/out) : Dump output.
2193  * ignore_length (in) : Length of recovery data.
2194  * data (in) : Recovery data.
2195  */
2196 void
2197 file_rv_dump_extdata_set_next (FILE * fp, int ignore_length, void *data)
2198 {
2199  VPID *vpid_next = (VPID *) data;
2200 
2201  fprintf (fp, "Set extensible data next page to %d|%d.\n", VPID_AS_ARGS (vpid_next));
2202 }
2203 
2204 /*
2205  * file_rv_extdata_add () - Add items to extensible data for recovery.
2206  *
2207  * return : NO_ERROR
2208  * thread_p (in) : Thread entry
2209  * rcv (in) : Recovery data
2210  */
2211 int
2213 {
2214  PAGE_PTR page_ftab = rcv->pgptr;
2215  FILE_EXTENSIBLE_DATA *extdata = NULL;
2216  int pos, count, offset = 0;
2217 
2218  assert (page_ftab != NULL);
2219  assert (rcv->offset >= 0 && rcv->offset < DB_PAGESIZE);
2220 
2221  pos = *(int *) (rcv->data + offset);
2222  offset += sizeof (pos);
2223 
2224  count = *(int *) (rcv->data + offset);
2225  offset += sizeof (count);
2226 
2227  extdata = (FILE_EXTENSIBLE_DATA *) (page_ftab + rcv->offset);
2228  assert (rcv->length == offset + extdata->size_of_item * count);
2229 
2230  file_extdata_insert_at (extdata, pos, count, rcv->data + offset);
2231 
2232  file_log ("file_rv_extdata_add",
2233  "add %d entries at position %d in page %d|%d, lsa %lld|%d \n"
2234  FILE_EXTDATA_MSG ("extdata after"), count, pos,
2235  PGBUF_PAGE_STATE_ARGS (page_ftab), FILE_EXTDATA_AS_ARGS (extdata));
2236 
2237  pgbuf_set_dirty (thread_p, page_ftab, DONT_FREE);
2238  return NO_ERROR;
2239 }
2240 
2241 /*
2242  * file_rv_extdata_remove () - Remove items from extensible data for recovery.
2243  *
2244  * return : NO_ERROR
2245  * thread_p (in) : Thread entry
2246  * rcv (in) : Recovery data
2247  */
2248 int
2250 {
2251  PAGE_PTR page_ftab = rcv->pgptr;
2252  FILE_EXTENSIBLE_DATA *extdata = NULL;
2253  int pos;
2254  int count;
2255  int offset = 0;
2256 
2257  assert (page_ftab != NULL);
2258  assert (rcv->offset >= 0 && rcv->offset < DB_PAGESIZE);
2259 
2260  pos = *(int *) (rcv->data + offset);
2261  offset += sizeof (pos);
2262 
2263  count = *(int *) (rcv->data + offset);
2264  offset += sizeof (count);
2265 
2266  assert (offset == rcv->length);
2267 
2268  extdata = (FILE_EXTENSIBLE_DATA *) (page_ftab + rcv->offset);
2269  file_extdata_remove_at (extdata, pos, count);
2270 
2271  file_log ("file_rv_extdata_remove",
2272  "remove %d entries at position %d in page %d|%d, lsa %lld|%d"
2273  FILE_EXTDATA_MSG ("extdata after"), count, pos,
2274  PGBUF_PAGE_STATE_ARGS (page_ftab), FILE_EXTDATA_AS_ARGS (extdata));
2275 
2276  pgbuf_set_dirty (thread_p, page_ftab, DONT_FREE);
2277  return NO_ERROR;
2278 }
2279 
2280 /*
2281  * file_rv_dump_extdata_add () - Dump add items to extensible data for recovery
2282  *
2283  * return : Void
2284  * fp (in) : Dump output
2285  * length (in) : Recovery data length
2286  * data (in) : Recovery data
2287  */
2288 void
2289 file_rv_dump_extdata_add (FILE * fp, int length, void *data)
2290 {
2291  int pos, count, offset = 0;
2292 
2293  pos = *(int *) ((char *) data + offset);
2294  offset += sizeof (pos);
2295 
2296  count = *(int *) ((char *) data + offset);
2297  offset += sizeof (count);
2298 
2299  fprintf (fp, "Add to extensible data at position = %d, count = %d.\n", pos, count);
2300  log_rv_dump_hexa (fp, length - offset, (char *) data + offset);
2301 }
2302 
2303 /*
2304  * file_rv_dump_extdata_remove () - Dump remove items from extensible data for recovery
2305  *
2306  * return : Void
2307  * fp (in) : Dump output
2308  * length (in) : Recovery data length
2309  * data (in) : Recovery data
2310  */
2311 void
2312 file_rv_dump_extdata_remove (FILE * fp, int length, void *data)
2313 {
2314  int pos, count, offset = 0;
2315 
2316  pos = *(int *) ((char *) data + offset);
2317  offset += sizeof (pos);
2318 
2319  count = *(int *) ((char *) data + offset);
2320  offset += sizeof (count);
2321  assert (length == offset);
2322 
2323  fprintf (fp, "Remove from extensible data at position = %d, count = %d.\n", pos, count);
2324 }
2325 
2326 /*
2327  * file_log_extdata_add () - Log adding items to extensible data
2328  *
2329  * return : Void
2330  * thread_p (in) : Thread entry
2331  * extdata (in) : Extensible data
2332  * page (in) : Page of extensible data
2333  * position (in) : Position in extensible data where items are added
2334  * count (in) : Item count
2335  * data (in) : Item(s)
2336  */
2337 STATIC_INLINE void
2339  const FILE_EXTENSIBLE_DATA * extdata, PAGE_PTR page, int position, int count, const void *data)
2340 {
2342  LOG_CRUMB crumbs[3];
2343 
2344  addr.pgptr = page;
2345  addr.offset = (PGLENGTH) (((char *) extdata) - page);
2346 
2347  crumbs[0].data = &position;
2348  crumbs[0].length = sizeof (position);
2349 
2350  crumbs[1].data = &count;
2351  crumbs[1].length = sizeof (count);
2352 
2353  crumbs[2].data = data;
2354  crumbs[2].length = extdata->size_of_item * count;
2355 
2356  log_append_undoredo_crumbs (thread_p, RVFL_EXTDATA_ADD, &addr, 2, 3, crumbs, crumbs);
2357  pgbuf_set_dirty (thread_p, page, DONT_FREE);
2358 }
2359 
2360 /*
2361  * file_log_extdata_remove () - Log removing items from extensible data
2362  *
2363  * return : Void
2364  * thread_p (in) : Thread entry
2365  * extdata (in) : Extensible data
2366  * page (in) : Page of extensible data
2367  * position (in) : Position in extensible data from where items are removed
2368  * count (in) : Item count
2369  */
2370 STATIC_INLINE void
2372  const FILE_EXTENSIBLE_DATA * extdata, PAGE_PTR page, int position, int count)
2373 {
2375  LOG_CRUMB crumbs[3];
2376 
2377  addr.pgptr = page;
2378  addr.offset = (PGLENGTH) (((char *) extdata) - page);
2379 
2380  crumbs[0].data = &position;
2381  crumbs[0].length = sizeof (position);
2382 
2383  crumbs[1].data = &count;
2384  crumbs[1].length = sizeof (count);
2385 
2386  crumbs[2].data = file_extdata_at (extdata, position);
2387  crumbs[2].length = extdata->size_of_item * count;
2388 
2389  log_append_undoredo_crumbs (thread_p, RVFL_EXTDATA_REMOVE, &addr, 3, 2, crumbs, crumbs);
2390  pgbuf_set_dirty (thread_p, page, DONT_FREE);
2391 }
2392 
2393 /*
2394  * file_log_extdata_set_next () - Log setting next page VPID into extensible data
2395  *
2396  * return : Void
2397  * thread_p (in) : Thread entry
2398  * extdata (in) : Extensible data
2399  * page (in) : Page of extensible data
2400  * vpid_next (in) : New value for next page VPID.
2401  */
2402 STATIC_INLINE void
2404  const VPID * vpid_next)
2405 {
2407  LOG_LSA save_lsa;
2408 
2409  addr.pgptr = page;
2410  addr.offset = (PGLENGTH) (((char *) extdata) - page);
2411  /* extdata should belong to page */
2412  assert (addr.offset >= 0 && addr.offset < DB_PAGESIZE);
2413 
2414  save_lsa = *pgbuf_get_lsa (page);
2415  log_append_undoredo_data (thread_p, RVFL_EXTDATA_SET_NEXT, &addr, sizeof (VPID), sizeof (VPID), &extdata->vpid_next,
2416  vpid_next);
2417 
2418  file_log ("file_log_extdata_set_next",
2419  "page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d, "
2420  "change extdata link to %d|%d, \n"
2421  FILE_EXTDATA_MSG ("extdata before"),
2422  PGBUF_PAGE_MODIFY_ARGS (page, &save_lsa), VPID_AS_ARGS (vpid_next), FILE_EXTDATA_AS_ARGS (extdata));
2423 
2424  pgbuf_set_dirty (thread_p, page, DONT_FREE);
2425 }
2426 
2427 /*
2428  * file_rv_extdata_merge () - recovery of merging extensible data components
2429  *
2430  * return : NO_ERROR
2431  * thread_p (in) : Thread entry
2432  * rcv (in) : Recovery data
2433  */
2434 int
2436 {
2437  FILE_EXTENSIBLE_DATA *extdata_in_page;
2438  FILE_EXTENSIBLE_DATA *extdata_in_rcv;
2439 
2440  assert (rcv->pgptr != NULL);
2441  assert (rcv->offset >= 0 && rcv->offset < DB_PAGESIZE);
2442 
2443  /* how it works:
2444  * the entire extensible data is logged before and after merge. so this is used for both undo and redo.
2445  */
2446 
2447  extdata_in_page = (FILE_EXTENSIBLE_DATA *) (rcv->pgptr + rcv->offset);
2448  extdata_in_rcv = (FILE_EXTENSIBLE_DATA *) rcv->data;
2449 
2450  assert (file_extdata_size (extdata_in_rcv) == rcv->length);
2451 
2452  /* overwrite extdata with recovery. */
2453  memcpy (extdata_in_page, extdata_in_rcv, rcv->length);
2454  pgbuf_set_dirty (thread_p, rcv->pgptr, DONT_FREE);
2455 
2456  file_log ("file_rv_extdata_merge", PGBUF_PAGE_STATE_MSG ("extensible data page") FILE_EXTDATA_MSG ("extdata after"),
2457  PGBUF_PAGE_STATE_ARGS (rcv->pgptr), FILE_EXTDATA_AS_ARGS (extdata_in_page));
2458 
2459  return NO_ERROR;
2460 }
2461 
2462 /*
2463  * file_extdata_update_item () - Update extensible data item and log the change.
2464  *
2465  * return : void
2466  * thread_p (in) : thread entry
2467  * page_extdata (in) : page of extensible data
2468  * item_newval (in) : new item value
2469  * index_item (in) : index to item being updated
2470  * extdata (in/out) : extensible data (one item is modified in this function)
2471  */
2472 STATIC_INLINE void
2473 file_extdata_update_item (THREAD_ENTRY * thread_p, PAGE_PTR page_extdata, const void *item_newval, int index_item,
2474  FILE_EXTENSIBLE_DATA * extdata)
2475 {
2476  char *item_in_page = (char *) file_extdata_at (extdata, index_item);
2477  PGLENGTH offset_in_page = (PGLENGTH) (item_in_page - page_extdata);
2478 
2479  log_append_undoredo_data2 (thread_p, RVFL_EXTDATA_UPDATE_ITEM, NULL, page_extdata, offset_in_page,
2480  extdata->size_of_item, extdata->size_of_item, item_in_page, item_newval);
2481 
2482  memcpy (item_in_page, item_newval, extdata->size_of_item);
2483  pgbuf_set_dirty (thread_p, page_extdata, DONT_FREE);
2484 }
2485 
2486 /*
2487  * file_extdata_merge_pages () - try to merge source extensible data page into destination extensible data page
2488  *
2489  * return : return true if pages have been merged, false otherwise
2490  * thread_p (in) : thread entry
2491  * extdata_src (in) : source extensible data
2492  * page_src (in) : source extensible data page
2493  * extdata_dest (in) : destination extensible data
2494  * page_dest (in) : destination extensible data page
2495  * compare_func (in) : compare function (required if items are ordered)
2496  * ordered (in) : true if items are ordered in pages (order must be preserved)
2497  */
2498 STATIC_INLINE bool
2499 file_extdata_merge_pages (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata_src, const PAGE_PTR page_src,
2500  FILE_EXTENSIBLE_DATA * extdata_dest, PAGE_PTR page_dest,
2501  int (*compare_func) (const void *, const void *), bool ordered)
2502 {
2504  LOG_LSA save_lsa = LSA_INITIALIZER;
2505 
2506  assert (extdata_dest != NULL && page_dest != NULL);
2507  assert ((char *) extdata_dest >= page_dest && (char *) extdata_dest < page_dest + DB_PAGESIZE);
2508  assert (extdata_src != NULL && page_src != NULL);
2509  assert ((char *) extdata_src >= page_src && (char *) extdata_src < page_src + DB_PAGESIZE);
2510  assert (!ordered || compare_func != NULL);
2512 
2513  if (!file_extdata_can_merge (extdata_src, extdata_dest))
2514  {
2515  /* not enough space */
2516  return false;
2517  }
2518 
2519  save_lsa = *pgbuf_get_lsa (page_dest);
2520  /* log previous extensible data */
2521  addr.pgptr = page_dest;
2522  addr.offset = (PGLENGTH) (((char *) extdata_dest) - page_dest);
2523  log_append_undo_data (thread_p, RVFL_EXTDATA_MERGE, &addr, file_extdata_size (extdata_dest), extdata_dest);
2524 
2525  if (ordered)
2526  {
2527  /* ordered merge */
2528  file_extdata_merge_ordered (extdata_src, extdata_dest, compare_func);
2529  }
2530  else
2531  {
2532  /* unordered merge */
2533  file_extdata_merge_unordered (extdata_src, extdata_dest);
2534  }
2535  /* update vpid_next */
2536  extdata_dest->vpid_next = extdata_src->vpid_next;
2537 
2538  /* log new extensible data */
2539  log_append_redo_data (thread_p, RVFL_EXTDATA_MERGE, &addr, file_extdata_size (extdata_dest), extdata_dest);
2540  pgbuf_set_dirty (thread_p, page_dest, DONT_FREE);
2541 
2542  file_log ("file_extdata_merge_pages", "merged extensible data: \n" FILE_EXTDATA_MSG ("extdata dest")
2543  "\t" PGBUF_PAGE_MODIFY_MSG ("page dest") "\n" FILE_EXTDATA_MSG ("extdata src")
2544  "\t" PGBUF_PAGE_STATE_MSG ("page src") "\n", FILE_EXTDATA_AS_ARGS (extdata_dest),
2545  PGBUF_PAGE_MODIFY_ARGS (page_dest, &save_lsa), FILE_EXTDATA_AS_ARGS (extdata_src),
2546  PGBUF_PAGE_STATE_ARGS (page_src));
2547 
2548  /* successful merge */
2549  return true;
2550 }
2551 
2552 /*
2553  * file_extdata_find_and_remove_item () - find an item in extensible data and remove it. if possible, also merge
2554  * extensible data pages
2555  *
2556  * return : error code
2557  * thread_p (in) : thread entry
2558  * extdata_first (in) : first extensible data
2559  * page_first (in) : first extensible data page
2560  * item (in) : item to find
2561  * compare_func (in) : compare function
2562  * ordered (in) : true if each extensible data page is ordered
2563  * item_pop (out) : if not NULL it will output the item removed from extensible data.
2564  * vpid_merged (out) : output the vpid if merged extensible data page or NULL vpid.
2565  */
2566 static int
2568  const void *item, int (*compare_func) (const void *, const void *), bool ordered,
2569  void *item_pop, VPID * vpid_merged)
2570 {
2571  PAGE_PTR page_prev = NULL;
2572  PAGE_PTR page_crt = NULL;
2573  FILE_EXTENSIBLE_DATA *extdata_prev = NULL;
2574  FILE_EXTENSIBLE_DATA *extdata_crt = NULL;
2575  bool found = false;
2576  int pos = 0;
2577  LOG_LSA save_lsa;
2578  int error_code = NO_ERROR;
2579 
2580  assert (extdata_first != NULL);
2581  assert (page_first != NULL);
2582  assert (item != NULL);
2583  assert (compare_func != NULL);
2584  assert (vpid_merged != NULL);
2586 
2587  /* how it works:
2588  *
2589  * first we must find the item in one of the extensible pages. we iterate through each page and try to find the item.
2590  * during page iteration we save the previous page (it is NULL when current page is first).
2591  *
2592  * if the items are ordered in each page, a binary search is executed. if not, items are compared one by one.
2593  *
2594  * when the item is found, it is removed from page. we also try to merge it with previous page or to merge next page
2595  * into current page. if merge is executed, the merged page vpid is output.
2596  *
2597  * if item_pop is not NULL, the removed item will be copied (note that the item is not always identical to search
2598  * item).
2599  */
2600 
2601  VPID_SET_NULL (vpid_merged);
2602 
2603  /* iterate through extensible data pages */
2604  extdata_crt = extdata_first;
2605  page_crt = page_first;
2606  while (true)
2607  {
2608  /* search item: do binary search if page is ordered, otherwise iterate through all until matched */
2609  if (ordered)
2610  {
2611  file_extdata_find_ordered (extdata_crt, item, compare_func, &found, &pos);
2612  }
2613  else
2614  {
2615  for (pos = 0; pos < file_extdata_item_count (extdata_crt); pos++)
2616  {
2617  if (compare_func (item, file_extdata_at (extdata_crt, pos)) == 0)
2618  {
2619  found = true;
2620  break;
2621  }
2622  }
2623  }
2624 
2625  if (found)
2626  {
2627  /* found item. remove it */
2628  assert (pos >= 0 && pos < file_extdata_item_count (extdata_crt));
2629 
2630  if (item_pop != NULL)
2631  {
2632  /* output item before removing */
2633  memcpy (item_pop, file_extdata_at (extdata_crt, pos), extdata_crt->size_of_item);
2634  }
2635 
2636  save_lsa = *pgbuf_get_lsa (page_crt);
2637  file_log_extdata_remove (thread_p, extdata_crt, page_crt, pos, 1);
2638  file_extdata_remove_at (extdata_crt, pos, 1);
2639 
2640  file_log ("file_extdata_find_and_remove_item", "removed extensible data item: \n"
2641  FILE_EXTDATA_MSG ("extensible data") "\t" PGBUF_PAGE_MODIFY_MSG ("extensible data page") "\n"
2642  "\tposition = %d \n", FILE_EXTDATA_AS_ARGS (extdata_crt),
2643  PGBUF_PAGE_MODIFY_ARGS (page_crt, &save_lsa), pos);
2644 
2645  if (page_prev != NULL)
2646  {
2647  /* try to merge to previous page */
2648  assert (extdata_prev != NULL);
2649 
2650  if (file_extdata_merge_pages (thread_p, extdata_crt, page_crt, extdata_prev, page_prev, compare_func,
2651  ordered))
2652  {
2653  pgbuf_get_vpid (page_crt, vpid_merged);
2654  /* we are done here */
2655  goto exit;
2656  }
2657  }
2658  }
2659  if (VPID_ISNULL (&extdata_crt->vpid_next))
2660  {
2661  break;
2662  }
2663  if (page_prev != NULL && page_prev != page_first)
2664  {
2665  pgbuf_unfix_and_init (thread_p, page_prev);
2666  }
2667  page_prev = page_crt;
2668  extdata_prev = extdata_crt;
2669  page_crt = pgbuf_fix (thread_p, &extdata_prev->vpid_next, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
2670  if (page_crt == NULL)
2671  {
2672  ASSERT_ERROR_AND_SET (error_code);
2673  goto exit;
2674  }
2675  extdata_crt = (FILE_EXTENSIBLE_DATA *) page_crt;
2676  if (found)
2677  {
2678  /* try to merge to previous page */
2679  if (file_extdata_merge_pages (thread_p, extdata_crt, page_crt, extdata_prev, page_prev, compare_func,
2680  ordered))
2681  {
2682  pgbuf_get_vpid (page_crt, vpid_merged);
2683  }
2684  break;
2685  }
2686  }
2687  if (!found)
2688  {
2689  /* item is missing which is unexpected */
2690  assert_release (false);
2691  error_code = ER_FAILED;
2692  goto exit;
2693  }
2694 
2695  assert (error_code == NO_ERROR);
2696 
2697 exit:
2698  assert (page_prev != page_crt);
2699 
2700  if (page_prev != NULL && page_prev != page_first)
2701  {
2702  pgbuf_unfix (thread_p, page_prev);
2703  }
2704  if (page_crt != NULL && page_crt != page_first)
2705  {
2706  pgbuf_unfix (thread_p, page_crt);
2707  }
2708  return error_code;
2709 }
2710 
2711 /*
2712  * file_extdata_all_item_count () - count items in all extensible data pages.
2713  *
2714  * return : error code
2715  * thread_p (in) : thread entry
2716  * extdata (in) : extensible data
2717  * count (out) : output total count of items
2718  */
2719 static int
2721 {
2722  return file_extdata_apply_funcs (thread_p, extdata, file_extdata_add_item_count, count, NULL, NULL, false, NULL,
2723  NULL);
2724 }
2725 
2726 /*
2727  * file_extdata_add_item_count () - FILE_EXTDATA_FUNC to count extensible data items.
2728  *
2729  * return : NO_ERROR
2730  * thread_p (in) : thread entry
2731  * extdata (in) : extensible data
2732  * stop (in) : ignored
2733  * args (in) : pointer to total count of items
2734  */
2735 static int
2736 file_extdata_add_item_count (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop, void *args)
2737 {
2738  (*((int *) args)) += file_extdata_item_count (extdata);
2739 
2740  return NO_ERROR;
2741 }
2742 
2743 /************************************************************************/
2744 /* Partially allocated sectors section */
2745 /************************************************************************/
2746 
2747 /*
2748  * file_partsect_is_full () - Is partial sector full?
2749  *
2750  * return : True if partial sector is full, false otherwise.
2751  * partsect (in) : Partial sector.
2752  */
2753 STATIC_INLINE bool
2755 {
2756  return partsect->page_bitmap == FILE_FULL_PAGE_BITMAP;
2757 }
2758 
2759 /*
2760  * file_partsect_is_empty () - Is partial sector empty?
2761  *
2762  * return : True if partial sector is empty, false otherwise.
2763  * partsect (in) : Partial sector.
2764  */
2765 STATIC_INLINE bool
2767 {
2768  return partsect->page_bitmap == FILE_EMPTY_PAGE_BITMAP;
2769 }
2770 
2771 /*
2772  * file_partsect_is_bit_set () - Is bit in partial sector bitmap set at offset?
2773  *
2774  * return : True if bit is set, false otherwise.
2775  * partsect (in) : Partial sector.
2776  * offset (in) : Offset to bit.
2777  */
2778 STATIC_INLINE bool
2780 {
2781  return bit64_is_set (partsect->page_bitmap, offset);
2782 }
2783 
2784 /*
2785  * file_partsect_set_bit () - Set bit in partial sector bitmap at offset. The bit is expected to be unset.
2786  *
2787  * return : Void.
2788  * partsect (in) : Partial sector.
2789  * offset (in) : Offset to bit.
2790  */
2791 STATIC_INLINE void
2793 {
2794  assert (!file_partsect_is_bit_set (partsect, offset));
2795 
2796  partsect->page_bitmap = bit64_set (partsect->page_bitmap, offset);
2797 }
2798 
2799 /*
2800  * file_partsect_clear_bit () - Clear bit in partial sector bitmap at offset. The bit is expected to be set.
2801  *
2802  * return : Void.
2803  * partsect (in) : Partial sector.
2804  * offset (in) : Offset to bit.
2805  */
2806 STATIC_INLINE void
2808 {
2809  assert (file_partsect_is_bit_set (partsect, offset));
2810 
2811  partsect->page_bitmap = bit64_clear (partsect->page_bitmap, offset);
2812 }
2813 
2814 /*
2815  * file_partsect_pageid_to_offset () - Convert pageid to offset in sector bitmap.
2816  *
2817  * return : Offset to bit in bitmap.
2818  * partsect (in) : Partial sector.
2819  * pageid (in) : Page ID.
2820  */
2821 STATIC_INLINE int
2823 {
2824  assert (SECTOR_FROM_PAGEID (pageid) == partsect->vsid.sectid);
2825 
2826  if (SECTOR_FROM_PAGEID (pageid) != partsect->vsid.sectid)
2827  {
2828  return -1;
2829  }
2830 
2831  return (int) (pageid - SECTOR_FIRST_PAGEID (partsect->vsid.sectid));
2832 }
2833 
2834 /*
2835  * file_partsect_alloc () - Try to allocate a page in partial sector.
2836  *
2837  * return : True if allocation was successful. False if the partial sector was actually full.
2838  * partsect (in/out) : Partial sector to allocate a page from. The allocated page bit is set afterwards.
2839  * vpid_out (out) : If not NULL, it outputs the VPID of allocated page.
2840  * offset_out (out) : If not NULL, it outputs the allocated page bit offset in bitmap.
2841  */
2842 STATIC_INLINE bool
2843 file_partsect_alloc (FILE_PARTIAL_SECTOR * partsect, VPID * vpid_out, int *offset_out)
2844 {
2845  int offset_to_zero = bit64_count_trailing_ones (partsect->page_bitmap);
2846 
2847  if (offset_to_zero >= FILE_ALLOC_BITMAP_NBITS)
2848  {
2849  assert (file_partsect_is_full (partsect));
2850  return false;
2851  }
2852 
2853  assert (offset_to_zero >= 0);
2854 
2855  file_partsect_set_bit (partsect, offset_to_zero);
2856  if (offset_out)
2857  {
2858  *offset_out = offset_to_zero;
2859  }
2860 
2861  if (vpid_out)
2862  {
2863  vpid_out->volid = partsect->vsid.volid;
2864  vpid_out->pageid = SECTOR_FIRST_PAGEID (partsect->vsid.sectid) + offset_to_zero;
2865  }
2866 
2867  return true;
2868 }
2869 
2870 /*
2871  * file_rv_partsect_update () - Set/clear bit in partial sector for recovery.
2872  *
2873  * return : Error code
2874  * thread_p (in) : Thread entry
2875  * rcv (in) : Recovery data
2876  * set (in) : True if bit should be set, false if bit should be cleared
2877  */
2878 static int
2879 file_rv_partsect_update (THREAD_ENTRY * thread_p, LOG_RCV * rcv, bool set)
2880 {
2881  PAGE_PTR page_ftab = rcv->pgptr;
2882  FILE_PARTIAL_SECTOR *partsect;
2883  int offset;
2884 
2885  assert (page_ftab != NULL);
2886  assert (rcv->offset >= 0 && rcv->offset < DB_PAGESIZE);
2887 
2888  offset = *(int *) rcv->data;
2889  assert (rcv->length == sizeof (offset));
2890 
2891  partsect = (FILE_PARTIAL_SECTOR *) (page_ftab + rcv->offset);
2892  if (set)
2893  {
2894  file_partsect_set_bit (partsect, offset);
2895  }
2896  else
2897  {
2898  file_partsect_clear_bit (partsect, offset);
2899  }
2900 
2901  file_log ("file_rv_partsect_update",
2902  "recovery partial sector update in page %d|%d prev_lsa %lld|%d: "
2903  "%s bit at offset %d, partial sector offset %d \n"
2904  FILE_PARTSECT_MSG ("partsect after rcv"),
2905  PGBUF_PAGE_STATE_ARGS (rcv->pgptr), set ? "set" : "clear", offset, rcv->offset,
2906  FILE_PARTSECT_AS_ARGS (partsect));
2907 
2908  pgbuf_set_dirty (thread_p, page_ftab, DONT_FREE);
2909  return NO_ERROR;
2910 }
2911 
2912 /*
2913  * file_rv_partsect_set () - Set bit in partial sector for recovery.
2914  *
2915  * return : Error code
2916  * thread_p (in) : Thread entry
2917  * rcv (in) : Recovery data
2918  */
2919 int
2921 {
2922  return file_rv_partsect_update (thread_p, rcv, true);
2923 }
2924 
2925 /*
2926  * file_rv_partsect_clear () - Clear bit in partial sector for recovery.
2927  *
2928  * return : Error code
2929  * thread_p (in) : Thread entry
2930  * rcv (in) : Recovery data
2931  */
2932 int
2934 {
2935  return file_rv_partsect_update (thread_p, rcv, false);
2936 }
2937 
2938 /************************************************************************/
2939 /* Utility functions. */
2940 /************************************************************************/
2941 
2942 /*
2943  * file_compare_vpids () - Compare two page identifiers.
2944  *
2945  * return : 1 if first page is bigger, -1 if first page is smaller and 0 if page ids are equal
2946  * first (in) : first page id
2947  * second (in) : second page id
2948  *
2949  * note: we need to ignore FILE_USER_PAGE_MARK_DELETED flag.
2950  */
2951 static int
2952 file_compare_vpids (const void *first, const void *second)
2953 {
2954  VPID first_vpid = *(VPID *) first;
2955  VPID second_vpid = *(VPID *) second;
2956 
2957  if (first_vpid.volid == second_vpid.volid)
2958  {
2959  FILE_USER_PAGE_CLEAR_MARK_DELETED (&first_vpid);
2960  FILE_USER_PAGE_CLEAR_MARK_DELETED (&second_vpid);
2961  return first_vpid.pageid - second_vpid.pageid;
2962  }
2963  else
2964  {
2965  return first_vpid.volid - second_vpid.volid;
2966  }
2967 }
2968 
2969 /*
2970  * file_compare_vfids () - Compare two file identifiers.
2971  *
2972  * return : positive if first file is bigger, negative if first file is smaller and 0 if page ids are equal
2973  * first (in) : first file id
2974  * second (in) : second file id
2975  *
2976  * note: we need to ignore FILE_USER_PAGE_MARK_DELETED flag.
2977  */
2978 static int
2979 file_compare_vfids (const void *first, const void *second)
2980 {
2981  VFID *first_vfid = (VFID *) first;
2982  VFID *second_vfid = (VFID *) second;
2983 
2984  if (first_vfid->volid > second_vfid->volid)
2985  {
2986  return 1;
2987  }
2988  if (first_vfid->volid < second_vfid->volid)
2989  {
2990  return -1;
2991  }
2992  return first_vfid->fileid - second_vfid->fileid;
2993 }
2994 
2995 /*
2996  * file_compare_track_items () - compare two file tracker items
2997  *
2998  * return : positive if first item is bigger, negative if first item is smaller, 0 if items are equal
2999  * first (in) : first item
3000  * second (in) : second item
3001  */
3002 static int
3003 file_compare_track_items (const void *first, const void *second)
3004 {
3005  FILE_TRACK_ITEM *first_item = (FILE_TRACK_ITEM *) first;
3006  FILE_TRACK_ITEM *second_item = (FILE_TRACK_ITEM *) second;
3007 
3008  if (first_item->volid > second_item->volid)
3009  {
3010  return 1;
3011  }
3012  if (first_item->volid < second_item->volid)
3013  {
3014  return -1;
3015  }
3016  return first_item->fileid - second_item->fileid;
3017 }
3018 
3019 /*
3020  * file_type_to_string () - Get a string of the given file type
3021  * return: string of the file type
3022  * fstruct_type(in): The type of the structure
3023  */
3024 const char *
3026 {
3027  switch (fstruct_type)
3028  {
3029  case FILE_TRACKER:
3030  return "TRACKER";
3031  case FILE_HEAP:
3032  return "HEAP";
3034  return "MULTIPAGE_OBJECT_HEAP";
3035  case FILE_BTREE:
3036  return "BTREE";
3038  return "BTREE_OVERFLOW_KEY";
3039  case FILE_EXTENDIBLE_HASH:
3040  return "HASH";
3042  return "HASH_DIRECTORY";
3043  case FILE_CATALOG:
3044  return "CATALOG";
3045  case FILE_DROPPED_FILES:
3046  return "DROPPED FILES";
3047  case FILE_VACUUM_DATA:
3048  return "VACUUM DATA";
3049  case FILE_QUERY_AREA:
3050  return "QUERY_AREA";
3051  case FILE_TEMP:
3052  return "TEMPORARILY";
3053  case FILE_UNKNOWN_TYPE:
3054  return "UNKNOWN";
3055  case FILE_HEAP_REUSE_SLOTS:
3056  return "HEAP_REUSE_SLOTS";
3057  }
3058  return "UNKNOWN";
3059 }
3060 
3061 static void
3062 file_print_name_of_class (THREAD_ENTRY * thread_p, FILE * fp, const OID * class_oid_p)
3063 {
3064  char *class_name_p = NULL;
3065 
3066  if (!OID_ISNULL (class_oid_p))
3067  {
3068  if (heap_get_class_name (thread_p, class_oid_p, &class_name_p) != NO_ERROR)
3069  {
3070  /* ignore */
3071  er_clear ();
3072  }
3073  fprintf (fp, "CLASS_OID: %5d|%10d|%5d (%s)", OID_AS_ARGS (class_oid_p),
3074  class_name_p != NULL ? class_name_p : "*UNKNOWN-CLASS*");
3075  if (class_name_p != NULL)
3076  {
3077  free_and_init (class_name_p);
3078  }
3079  }
3080 }
3081 
3082 /************************************************************************/
3083 /* File manipulation section. */
3084 /************************************************************************/
3085 
3086 /*
3087  * file_create_with_npages () - Create a permanent file big enough to store a number of pages.
3088  *
3089  * return : Error code
3090  * thread_p (in) : Thread entry
3091  * file_type (in) : File type
3092  * npages (in) : Number of pages.
3093  * des (in) : File descriptor.
3094  * vfid (out) : File identifier.
3095  */
3096 int
3097 file_create_with_npages (THREAD_ENTRY * thread_p, FILE_TYPE file_type, int npages, FILE_DESCRIPTORS * des, VFID * vfid)
3098 {
3100 
3101  assert (file_type != FILE_TEMP);
3102 
3103  assert (npages > 0);
3104 
3105  FILE_TABLESPACE_FOR_PERM_NPAGES (&tablespace, npages);
3106 
3107  return file_create (thread_p, file_type, &tablespace, des, false, false, vfid);
3108 }
3109 
3110 /*
3111  * file_create_heap () - Create heap file (permanent, not numerable)
3112  *
3113  * return : Error code
3114  * thread_p (in) : Thread entry
3115  * reuse_oid (in) : Reuse slots true or false
3116  * class_oid (in) : Class identifier
3117  * vfid (out) : File identifier
3118  *
3119  * todo: add tablespace.
3120  */
3121 int
3122 file_create_heap (THREAD_ENTRY * thread_p, bool reuse_oid, const OID * class_oid, VFID * vfid)
3123 {
3124  FILE_DESCRIPTORS des;
3125  FILE_TYPE file_type = reuse_oid ? FILE_HEAP_REUSE_SLOTS : FILE_HEAP;
3126 
3127  assert (class_oid != NULL);
3128 
3129  /* it's done this way because of annoying Valgrind complaints: */
3130  memset (&des, 0, sizeof (des));
3131  /* set class_oid here */
3132  des.heap.class_oid = *class_oid;
3133  /* hfid will be updated after create */
3134 
3135  return file_create_with_npages (thread_p, file_type, 1, &des, vfid);
3136 }
3137 
3138 /*
3139  * file_create_temp_internal () - common function to create files for temporary purpose. always try to use a cached
3140  * temporary file first. if there is no cached entry, create a new file.
3141  * in the end save the temp cache entry in transaction list of temporary files.
3142  *
3143  * return : error code
3144  * thread_p (in) : thread entry
3145  * npages (in) : desired number of pages (ignored when taking file from cache)
3146  * ftype (in) : file type
3147  * is_numerable (in) : true if file must be numerable, false if should be regular file
3148  * vfid_out (out) : VFID of file (obtained from cache or created).
3149  */
3150 STATIC_INLINE int
3151 file_create_temp_internal (THREAD_ENTRY * thread_p, int npages, FILE_TYPE ftype, bool is_numerable, VFID * vfid_out)
3152 {
3154  FILE_TEMPCACHE_ENTRY *tempcache_entry = NULL;
3155  int error_code = NO_ERROR;
3156 
3157  assert (npages > 0);
3158 
3159  error_code = file_tempcache_get (thread_p, ftype, is_numerable, &tempcache_entry);
3160  if (error_code != NO_ERROR)
3161  {
3162  ASSERT_ERROR ();
3163  return error_code;
3164  }
3165  assert (tempcache_entry != NULL);
3166  assert (tempcache_entry->ftype == ftype);
3167 
3168  if (VFID_ISNULL (&tempcache_entry->vfid))
3169  {
3170  FILE_TABLESPACE_FOR_TEMP_NPAGES (&tablespace, npages);
3171  error_code = file_create (thread_p, ftype, &tablespace, NULL, true, is_numerable, vfid_out);
3172  if (error_code != NO_ERROR)
3173  {
3174  ASSERT_ERROR ();
3175  file_tempcache_retire_entry (tempcache_entry);
3176  return error_code;
3177  }
3178  tempcache_entry->vfid = *vfid_out;
3179  }
3180  else
3181  {
3182  /* we use the cached file */
3183  /* what about the number of pages? */
3184  *vfid_out = tempcache_entry->vfid;
3185  }
3186 
3187  /* save to transaction temporary file list */
3188  file_tempcache_push_tran_file (thread_p, tempcache_entry);
3189  return NO_ERROR;
3190 }
3191 
3192 /*
3193  * file_create_temp () - Create a temporary file.
3194  *
3195  * return : Error code
3196  * thread_p (in) : Thread entry
3197  * npages (in) : Number of pages
3198  * vfid (out) : File identifier
3199  */
3200 int
3201 file_create_temp (THREAD_ENTRY * thread_p, int npages, VFID * vfid)
3202 {
3203  return file_create_temp_internal (thread_p, npages, FILE_TEMP, false, vfid);
3204 }
3205 
3206 /*
3207  * file_create_temp_numerable () - Create a temporary file with numerable property.
3208  *
3209  * return : Error code
3210  * thread_p (in) : Thread entry
3211  * npages (in) : Number of pages
3212  * vfid (out) : File identifier
3213  */
3214 int
3215 file_create_temp_numerable (THREAD_ENTRY * thread_p, int npages, VFID * vfid)
3216 {
3217  return file_create_temp_internal (thread_p, npages, FILE_TEMP, true, vfid);
3218 }
3219 
3220 /*
3221  * file_create_query_area () - Create a query area file (temporary, not numerable).
3222  *
3223  * return : Error code
3224  * thread_p (in) : Thread entry
3225  * vfid (out) : File identifier
3226  */
3227 int
3229 {
3230  return file_create_temp_internal (thread_p, 1, FILE_QUERY_AREA, false, vfid);
3231 }
3232 
3233 /*
3234  * file_create_ehash () - Create a permanent or temporary file for extensible hash table. This file will have the
3235  * numerable property.
3236  *
3237  * return : Error code
3238  * thread_p (in) : Thread entry
3239  * npages (in) : Number of pages
3240  * is_tmp (in) : True if is temporary, false if is permanent
3241  * des_ehash (in) : Extensible hash descriptor.
3242  * vfid (out) : File identifier.
3243  */
3244 int
3245 file_create_ehash (THREAD_ENTRY * thread_p, int npages, bool is_tmp, FILE_EHASH_DES * des_ehash, VFID * vfid)
3246 {
3248 
3249  assert (npages > 0);
3250 
3251  /* todo: use temporary file cache? */
3252 
3253  FILE_TABLESPACE_FOR_TEMP_NPAGES (&tablespace, npages);
3254  return file_create (thread_p, FILE_EXTENDIBLE_HASH, &tablespace, (FILE_DESCRIPTORS *) des_ehash, is_tmp, true, vfid);
3255 }
3256 
3257 /*
3258  * file_create_ehash_dir () - Create a permanent or temporary file for extensible hash directory. This file will have
3259  * the numerable property.
3260  *
3261  * return : Error code
3262  * thread_p (in) : Thread entry
3263  * npages (in) : Number of pages
3264  * is_tmp (in) : True if is temporary, false if is permanent
3265  * des_ehash (in) : Extensible hash descriptor.
3266  * vfid (out) : File identifier.
3267  */
3268 int
3269 file_create_ehash_dir (THREAD_ENTRY * thread_p, int npages, bool is_tmp, FILE_EHASH_DES * des_ehash, VFID * vfid)
3270 {
3272 
3273  assert (npages > 0);
3274 
3275  /* todo: use temporary file cache? */
3276 
3277  FILE_TABLESPACE_FOR_TEMP_NPAGES (&tablespace, npages);
3278  return file_create (thread_p, FILE_EXTENDIBLE_HASH_DIRECTORY, &tablespace, (FILE_DESCRIPTORS *) des_ehash, is_tmp,
3279  true, vfid);
3280 }
3281 
3282 /*
3283  * file_create () - Create a new file.
3284  *
3285  * return : Error code.
3286  * thread_p (in) : Thread entry.
3287  * file_type (in) : File type.
3288  * tablespace (in) : File table space.
3289  * des (in) : File descriptor (based on file type).
3290  * is_temp (in) : True if file should be temporary.
3291  * is_numerable (in) : True if file should be numerable.
3292  * vfid (out) : Output new file identifier.
3293  */
3294 int
3295 file_create (THREAD_ENTRY * thread_p, FILE_TYPE file_type,
3296  FILE_TABLESPACE * tablespace, FILE_DESCRIPTORS * des, bool is_temp, bool is_numerable, VFID * vfid)
3297 {
3298  INT64 total_size;
3299  int n_sectors;
3300  VSID *vsids_reserved = NULL;
3301  bool was_temp_reserved = false;
3302  DB_VOLPURPOSE volpurpose = DISK_UNKNOWN_PURPOSE;
3303  VSID *vsid_iter = NULL;
3304  INT16 size = 0;
3306 
3307  /* File header vars */
3308  VPID vpid_fhead = VPID_INITIALIZER;
3309  PAGE_PTR page_fhead = NULL;
3310  FILE_HEADER *fhead = NULL;
3311 
3312  /* File table vars */
3313  INT64 max_size_ftab;
3314  FILE_PARTIAL_SECTOR *partsect_ftab = NULL;
3315  VPID vpid_ftab = VPID_INITIALIZER;
3316  PAGE_PTR page_ftab = NULL;
3317  bool found_vfid_page = false;
3318  INT16 offset_ftab = 0;
3319 
3320  /* Partial table. */
3321  FILE_PARTIAL_SECTOR partsect;
3322 
3323  /* File extensible data */
3324  FILE_EXTENSIBLE_DATA *extdata_part_ftab = NULL;
3325  FILE_EXTENSIBLE_DATA *extdata_part_ftab_in_fhead = NULL;
3326  FILE_EXTENSIBLE_DATA *extdata_full_ftab = NULL;
3327  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab = NULL;
3328 
3329  /* Recovery */
3330  bool is_sysop_started = false;
3331  bool do_logging = !is_temp;
3332 
3333  int error_code = NO_ERROR;
3334 
3335  assert (tablespace->initial_size > 0);
3336  assert (file_type != FILE_TEMP || is_temp);
3337  assert (vfid != NULL);
3338 
3339  /* Estimate the required size including file header & tables. */
3340  total_size = tablespace->initial_size;
3341 
3342  if (!is_numerable)
3343  {
3344  /* Partial & full sectors tables.
3345  * The worst case is when all sectors are partially allocated. The required size will be sizeof (SECTOR_ID) and
3346  * the size of bitmap (in bytes), which counts to 16 bytes, for each sector. The sector size will be at least
3347  * 4k * 64 => 256KB. So we need to increase the total size of file with 16 bytes per every 256KB, or 1 byte for
3348  * each 16KB. Then we need again to consider the additional space used by table (another 1 byte for 16KB x 16 KB).
3349  * This of course translates to an infinite series and we want to simplify that. So, adding 1 byte for each 8KB
3350  * from the start should cover any space required by file tables.
3351  */
3352  max_size_ftab = total_size / 8 / 1024;
3353  total_size += max_size_ftab;
3354  }
3355  else
3356  {
3357  /* Partial & full sectors tables + page table.
3358  * By applying the same logic above, we consider the worst case (which is impossible actually) all sectors are
3359  * partially allocated (16 bytes per sector) and all pages are allocated by user (64 * 8 byte per sector). This
3360  * totals to 528 bytes for each 256KB bytes of data. By doubling the estimated size of tables, we need an extra
3361  * 1 byte for each 256KB / 528 / 2, which is equivalent to 1 byte for each 8/33 KB.
3362  */
3363  max_size_ftab = total_size * 33 / 8 / 1024;
3364  total_size += max_size_ftab;
3365  }
3366 
3367  /* convert the disk size to number of sectors. */
3368  n_sectors = (int) CEIL_PTVDIV (total_size, DB_SECTORSIZE);
3369  assert (n_sectors > 0);
3370  /* allocate a buffer to store all reserved sectors */
3371  vsids_reserved = (VSID *) db_private_alloc (thread_p, n_sectors * sizeof (VSID));
3372  if (vsids_reserved == NULL)
3373  {
3375  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3376  goto exit;
3377  }
3378 
3379  if (do_logging)
3380  {
3381  /* start a system operation */
3382  log_sysop_start (thread_p);
3383  is_sysop_started = true;
3384  }
3385 
3386  /* reserve sectors on disk */
3387  volpurpose = is_temp ? DB_TEMPORARY_DATA_PURPOSE : DB_PERMANENT_DATA_PURPOSE;
3388 
3389  file_log ("file_create",
3390  "create %s file \n\t%s \n\t%s \n" FILE_TABLESPACE_MSG
3391  " \tnsectors = %d", file_type_to_string (file_type),
3392  FILE_PERM_TEMP_STRING (is_temp),
3393  FILE_NUMERABLE_REGULAR_STRING (is_numerable), FILE_TABLESPACE_AS_ARGS (tablespace), n_sectors);
3394 
3395  error_code = disk_reserve_sectors (thread_p, volpurpose, NULL_VOLID, n_sectors, vsids_reserved);
3396  if (error_code != NO_ERROR)
3397  {
3398  ASSERT_ERROR ();
3399  goto exit;
3400  }
3401  /* found enough sectors to reserve */
3402  was_temp_reserved = is_temp;
3403 
3404  /* sort sectors by VSID. but before sorting, remember last volume ID used for reservations. */
3405  volid_last_expand = vsids_reserved[n_sectors - 1].volid;
3406  qsort (vsids_reserved, n_sectors, sizeof (VSID), disk_compare_vsids);
3407 
3408  /* decide on what page to use as file header page (which is going to decide the VFID also). */
3409 #if defined (SERVER_MODE)
3410  if (file_type == FILE_BTREE || file_type == FILE_HEAP || file_type == FILE_HEAP_REUSE_SLOTS)
3411  {
3412  /* we need to consider dropped files in vacuum's list. If we create a file with a duplicate VFID, we can run
3413  * into problems. */
3414  VSID *vsid_iter = vsids_reserved;
3415  VFID vfid_iter;
3416  VFID found_vfid = VFID_INITIALIZER;
3417  MVCCID tran_mvccid = logtb_get_current_mvccid (thread_p);
3418  /* we really have to have the VFID in the same volume as the first allocated page. this means we cannot change
3419  * volume when we look for a valid VFID. */
3420  VOLID first_volid = vsids_reserved[0].volid;
3421  bool is_file_dropped;
3422 
3423  for (vsid_iter = vsids_reserved;
3424  vsid_iter < vsids_reserved + n_sectors && VFID_ISNULL (&found_vfid)
3425  && vsid_iter->volid == first_volid; vsid_iter++)
3426  {
3427  vfid_iter.volid = vsid_iter->volid;
3428  for (vfid_iter.fileid = SECTOR_FIRST_PAGEID (vsid_iter->sectid);
3429  vfid_iter.fileid <= SECTOR_LAST_PAGEID (vsid_iter->sectid); vfid_iter.fileid++)
3430  {
3431  error_code = vacuum_is_file_dropped (thread_p, &is_file_dropped, &vfid_iter, tran_mvccid);
3432  if (error_code != NO_ERROR)
3433  {
3434  ASSERT_ERROR ();
3435  goto exit;
3436  }
3437 
3438  if (is_file_dropped == false)
3439  {
3440  /* Good we found a file ID that is not considered dropped. */
3441  found_vfid = vfid_iter;
3442  break;
3443  }
3444  }
3445  }
3446  if (VFID_ISNULL (&found_vfid))
3447  {
3448  /* this is ridiculous. */
3449  assert_release (false);
3450  error_code = ER_FAILED;
3451  goto exit;
3452  }
3453  *vfid = found_vfid;
3454  }
3455  else
3456 #endif /* SERVER_MODE */
3457  {
3458  vfid->volid = vsids_reserved->volid;
3459  vfid->fileid = SECTOR_FIRST_PAGEID (vsids_reserved->sectid);
3460  }
3461 
3462  assert (!VFID_ISNULL (vfid));
3463  vpid_fhead.volid = vfid->volid;
3464  vpid_fhead.pageid = vfid->fileid;
3465 
3466  file_log ("file_create", "chose VFID = %d|%d.", VFID_AS_ARGS (vfid));
3467 
3468  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
3469  if (page_fhead == NULL)
3470  {
3471  ASSERT_ERROR_AND_SET (error_code);
3472  goto exit;
3473  }
3474 
3475  memset (page_fhead, 0, DB_PAGESIZE);
3476  pgbuf_set_page_ptype (thread_p, page_fhead, PAGE_FTAB);
3477  fhead = (FILE_HEADER *) page_fhead;
3478 
3479  /* initialize header */
3480  fhead->self = *vfid;
3481  fhead->tablespace = *tablespace;
3482  if (des != NULL)
3483  {
3484  fhead->descriptor = *des;
3485  }
3486  fhead->time_creation = time (NULL);
3487  fhead->type = file_type;
3488  fhead->file_flags = 0;
3489  if (is_numerable)
3490  {
3491  fhead->file_flags |= FILE_FLAG_NUMERABLE;
3492  }
3493  if (is_temp)
3494  {
3495  fhead->file_flags |= FILE_FLAG_TEMPORARY;
3496  }
3497 
3503  fhead->first_index_find_nth_last = 0;
3504  VPID_SET_NULL (&fhead->vpid_sticky_first);
3505 
3506  fhead->n_page_total = 0;
3507  fhead->n_page_user = 0;
3508  fhead->n_page_ftab = 1; /* file header */
3509  fhead->n_page_free = 0;
3510  fhead->n_page_mark_delete = 0;
3511 
3512  fhead->n_sector_total = 0;
3513  fhead->n_sector_partial = 0;
3514  fhead->n_sector_full = 0;
3515  fhead->n_sector_empty = 0;
3516 
3520 
3521  fhead->reserved0 = 0;
3522  fhead->reserved1 = 0;
3523  fhead->reserved2 = 0;
3524  fhead->reserved3 = 0;
3525 
3526  /* start with a negative empty sector (because we have allocated header). */
3527  fhead->n_sector_empty--;
3528 
3529  /* start creating required file tables.
3530  * file tables depend of the properties of permanent/temporary and numerable.
3531  * temporary files do not use full table, only partial table. permanent files use both partial and full tables.
3532  * numerable files (which can be both permanent or temporary) also require user page table.
3533  */
3534  offset_ftab = FILE_HEADER_ALIGNED_SIZE;
3535  if (is_numerable)
3536  {
3537  if (is_temp)
3538  {
3539  /* split the header page space into: 1/16 for partial table and 15/16 for user page table */
3540  fhead->offset_to_partial_ftab = offset_ftab;
3542  size = (DB_PAGESIZE - offset_ftab) / 16;
3543  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
3544  file_extdata_init (sizeof (FILE_PARTIAL_SECTOR), size, extdata_part_ftab);
3545 
3546  offset_ftab += file_extdata_max_size (extdata_part_ftab);
3547  }
3548  else
3549  {
3550  /* split the header space into three: 1/32 for each partial and full sector tables and the rest (15/16) for
3551  * user page table. */
3552 
3553  /* partial table. */
3554  fhead->offset_to_partial_ftab = offset_ftab;
3556  size = (DB_PAGESIZE - offset_ftab) / 32;
3557  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
3558  file_extdata_init (sizeof (FILE_PARTIAL_SECTOR), size, extdata_part_ftab);
3559 
3560  /* full table. */
3561  offset_ftab += file_extdata_max_size (extdata_part_ftab);
3562  fhead->offset_to_full_ftab = offset_ftab;
3564  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_full_ftab);
3565  file_extdata_init (sizeof (VSID), size, extdata_full_ftab);
3566 
3567  offset_ftab += file_extdata_max_size (extdata_full_ftab);
3568  }
3569 
3570  /* user page table - consume remaining space. */
3571  fhead->offset_to_user_page_ftab = offset_ftab;
3573  size = DB_PAGESIZE - offset_ftab;
3574  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
3575  file_extdata_init (sizeof (VPID), size, extdata_user_page_ftab);
3576  }
3577  else
3578  {
3579  if (is_temp)
3580  {
3581  /* keep only partial table. */
3582  fhead->offset_to_partial_ftab = offset_ftab;
3584  size = DB_PAGESIZE - offset_ftab;
3585  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
3586  file_extdata_init (sizeof (FILE_PARTIAL_SECTOR), size, extdata_part_ftab);
3587  }
3588  else
3589  {
3590  /* split the header space into two: half for partial table and half for full table. */
3591 
3592  /* partial table. */
3593  fhead->offset_to_partial_ftab = offset_ftab;
3595  size = (DB_PAGESIZE - offset_ftab) / 2;
3596  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
3597  file_extdata_init (sizeof (FILE_PARTIAL_SECTOR), size, extdata_part_ftab);
3598 
3599  /* full table. */
3600  offset_ftab += file_extdata_max_size (extdata_part_ftab);
3601  fhead->offset_to_full_ftab = offset_ftab;
3603  size = DB_PAGESIZE - offset_ftab;
3604  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_full_ftab);
3605  file_extdata_init (sizeof (VSID), size, extdata_full_ftab);
3606  }
3607  }
3608  /* all required tables are created */
3609  /* all files must have partial table */
3611 
3612  /* start populating partial table */
3613  /* partial sectors are initially added to the table in header. if the file is really big, and the table needs to
3614  * extend on other pages, we will keep track of pages/sectors used for file table using extdata_part_ftab.
3615  */
3616  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
3617  extdata_part_ftab_in_fhead = extdata_part_ftab;
3618  for (vsid_iter = vsids_reserved; vsid_iter < vsids_reserved + n_sectors; vsid_iter++)
3619  {
3620  if (file_extdata_is_full (extdata_part_ftab))
3621  {
3622  /* a new page for file table is required */
3623 
3624  /* allocate a page from partial table. */
3625  if (partsect_ftab == NULL)
3626  {
3627  /* This is first page. */
3628  assert (!file_extdata_is_empty (extdata_part_ftab));
3629  partsect_ftab = (FILE_PARTIAL_SECTOR *) file_extdata_start (extdata_part_ftab);
3630  vpid_ftab.pageid = SECTOR_FIRST_PAGEID (partsect_ftab->vsid.sectid);
3631  vpid_ftab.volid = partsect_ftab->vsid.volid;
3632 
3633  if (!VSID_IS_SECTOR_OF_VPID (&partsect_ftab->vsid, &vpid_fhead))
3634  {
3635  /* another non-empty sector. */
3636  fhead->n_sector_empty--;
3637  }
3638  else
3639  {
3640  /* this non-empty sector was already counted */
3641  }
3642  }
3643  else if (file_partsect_is_full (partsect_ftab))
3644  {
3645  /* move to next partial sector. */
3646  partsect_ftab++;
3647  if ((void *) partsect_ftab >= file_extdata_end (extdata_part_ftab_in_fhead))
3648  {
3649  /* This is not possible! */
3650  assert_release (false);
3651  error_code = ER_FAILED;
3652  goto exit;
3653  }
3654  vpid_ftab.pageid = SECTOR_FIRST_PAGEID (partsect_ftab->vsid.sectid);
3655  vpid_ftab.volid = partsect_ftab->vsid.volid;
3656 
3657  if (!VSID_IS_SECTOR_OF_VPID (&partsect_ftab->vsid, &vpid_fhead))
3658  {
3659  /* another non-empty sector. */
3660  fhead->n_sector_empty--;
3661  }
3662  else
3663  {
3664  /* this non-empty sector was already counted */
3665  }
3666 
3667  fhead->n_sector_full++;
3668  }
3669  else
3670  {
3671  vpid_ftab.pageid++;
3672  }
3673 
3674  if (VPID_EQ (&vpid_fhead, &vpid_ftab))
3675  {
3676  /* Go to next page. This can't be last page in sector, because the sector bitmap would have been full */
3677  assert (file_partsect_is_bit_set (partsect_ftab,
3678  file_partsect_pageid_to_offset (partsect_ftab, vpid_fhead.pageid)));
3679  vpid_ftab.pageid++;
3680  found_vfid_page = true;
3681  }
3682  /* Set bit in sector bitmap */
3683  file_partsect_set_bit (partsect_ftab, file_partsect_pageid_to_offset (partsect_ftab, vpid_ftab.pageid));
3684 
3685  /* Save link in previous page. */
3686  extdata_part_ftab->vpid_next = vpid_ftab;
3687  if (page_ftab != NULL)
3688  {
3689  if (do_logging)
3690  {
3691  pgbuf_log_new_page (thread_p, page_ftab, file_extdata_size (extdata_part_ftab), PAGE_FTAB);
3692  }
3693  pgbuf_set_dirty (thread_p, page_ftab, FREE);
3694  }
3695  page_ftab = pgbuf_fix (thread_p, &vpid_ftab, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
3696  if (page_ftab == NULL)
3697  {
3698  ASSERT_ERROR_AND_SET (error_code);
3699  goto exit;
3700  }
3701  pgbuf_set_page_ptype (thread_p, page_ftab, PAGE_FTAB);
3702  memset (page_ftab, 0, DB_PAGESIZE);
3703  extdata_part_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
3704  file_extdata_init (sizeof (FILE_PARTIAL_SECTOR), DB_PAGESIZE, extdata_part_ftab);
3705 
3706  fhead->n_page_ftab++;
3707  }
3708  assert (!file_extdata_is_full (extdata_part_ftab));
3709 
3710  partsect.vsid = *vsid_iter;
3712  if (partsect.vsid.sectid == SECTOR_FROM_PAGEID (vpid_fhead.pageid) && partsect.vsid.volid == vpid_fhead.volid)
3713  {
3714  /* Set bit for file header page. */
3715  file_partsect_set_bit (&partsect, file_partsect_pageid_to_offset (&partsect, vpid_fhead.pageid));
3716  }
3717  file_extdata_append (extdata_part_ftab, &partsect);
3718  }
3719 
3720  if (page_ftab != NULL)
3721  {
3722  if (do_logging)
3723  {
3724  pgbuf_log_new_page (thread_p, page_ftab, file_extdata_size (extdata_part_ftab), PAGE_FTAB);
3725  pgbuf_unfix_and_init (thread_p, page_ftab);
3726  }
3727  else
3728  {
3729  pgbuf_set_dirty_and_free (thread_p, page_ftab);
3730  }
3731  }
3732 
3733  if (partsect_ftab == NULL)
3734  {
3735  /* all partial sectors were fitted in header page */
3736  assert (fhead->n_sector_full == 0);
3737  }
3738  else
3739  {
3740  if (file_partsect_is_full (partsect_ftab))
3741  {
3742  partsect_ftab++;
3743  fhead->n_sector_full++;
3744  }
3745  if (!is_temp && fhead->n_sector_full > 0)
3746  {
3747  /* move sectors fully used by file table to full table */
3748  int i;
3749  FILE_PARTIAL_SECTOR *partsect_iter;
3750  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
3751  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_full_ftab);
3752 
3753  for (i = 0; i < fhead->n_sector_full; i++)
3754  {
3755  partsect_iter = (FILE_PARTIAL_SECTOR *) file_extdata_at (extdata_part_ftab, i);
3756  if (file_extdata_is_full (extdata_full_ftab))
3757  {
3758  /* Not possible. */
3759  assert_release (false);
3760  error_code = ER_FAILED;
3761  goto exit;
3762  }
3763  file_extdata_append (extdata_full_ftab, &partsect_iter->vsid);
3764  }
3765  /* Remove full sectors from partial table. */
3766  file_extdata_remove_at (extdata_part_ftab, 0, fhead->n_sector_full);
3767  assert (fhead->n_sector_full == file_extdata_item_count (extdata_full_ftab));
3768  }
3769  }
3770 
3771  if (is_temp)
3772  {
3773  /* temporary files do not keep separate tables for partial and full sectors. just set last allocation location. */
3774  VPID_COPY (&fhead->vpid_last_temp_alloc, &vpid_fhead);
3775  fhead->offset_to_last_temp_alloc = fhead->n_sector_full;
3776  }
3777 
3778  if (is_numerable)
3779  {
3780  /* set last user page table VPID to header */
3781  fhead->vpid_last_user_page_ftab = vpid_fhead;
3782  fhead->vpid_find_nth_last = vpid_fhead;
3783  }
3784 
3785  /* set all stats */
3786  /* sector stats; full stats already counted, empty stats are negative (we need to add partial sectors) */
3787  fhead->n_sector_total = n_sectors;
3788  fhead->n_sector_partial = fhead->n_sector_total - fhead->n_sector_full;
3789  fhead->n_sector_empty += fhead->n_sector_partial;
3790  /* page stats; file table pages already counted; user pages remain 0 */
3792  fhead->n_page_free = fhead->n_page_total - fhead->n_page_ftab;
3793 
3794  /* File header ready. */
3795  file_header_sanity_check (thread_p, fhead);
3796 
3797  file_log ("file_create", "finished creating file. \n" FILE_HEAD_FULL_MSG, FILE_HEAD_FULL_AS_ARGS (fhead));
3798 
3799  if (do_logging)
3800  {
3801  pgbuf_log_new_page (thread_p, page_fhead, DB_PAGESIZE, PAGE_FTAB);
3802  pgbuf_unfix_and_init (thread_p, page_fhead);
3803  }
3804  else
3805  {
3806  pgbuf_set_dirty_and_free (thread_p, page_fhead);
3807  }
3808 
3809  if (!is_temp && file_type != FILE_TRACKER)
3810  {
3811  /* add to tracker */
3812  error_code = file_tracker_register (thread_p, vfid, file_type, NULL);
3813  if (error_code != NO_ERROR)
3814  {
3815  ASSERT_ERROR ();
3816  goto exit;
3817  }
3818  }
3819 
3820  if (is_temp)
3821  {
3822  /* update stats */
3823  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.nfile, 1);
3824  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_ftab, fhead->n_page_ftab);
3825  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_user, fhead->n_page_user);
3826  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_reserved, fhead->n_page_free);
3827  }
3828 
3829  /* Fall through to exit */
3830 exit:
3831 
3832  if (page_ftab != NULL)
3833  {
3834  pgbuf_unfix (thread_p, page_ftab);
3835  }
3836  if (page_fhead != NULL)
3837  {
3838  pgbuf_unfix (thread_p, page_fhead);
3839  }
3840 
3841  if (is_sysop_started)
3842  {
3843  assert (do_logging);
3844  if (error_code != NO_ERROR)
3845  {
3846  ASSERT_ERROR ();
3847  log_sysop_abort (thread_p);
3848  }
3849  else
3850  {
3851  log_sysop_end_logical_undo (thread_p, RVFL_DESTROY, NULL, sizeof (*vfid), (char *) vfid);
3852  }
3853  }
3854 
3855  if (error_code != NO_ERROR)
3856  {
3857  /* make sure we don't output a bad VFID. */
3858  VFID_SET_NULL (vfid);
3859 
3860  if (was_temp_reserved)
3861  {
3862  /* recovery won't free reserved sectors. we have to manually handle the unreserve */
3863  bool save_check_interrupt = logtb_set_check_interrupt (thread_p, false);
3864 
3865  /* make sure sectors are sorted */
3866  qsort (vsids_reserved, n_sectors, sizeof (VSID), disk_compare_vsids);
3867  if (disk_unreserve_ordered_sectors (thread_p, DB_TEMPORARY_DATA_PURPOSE, n_sectors, vsids_reserved)
3868  != NO_ERROR)
3869  {
3870  /* sectors are leaked */
3871  assert_release (false);
3872  /* fall through */
3873  }
3874  (void) logtb_set_check_interrupt (thread_p, save_check_interrupt);
3875  }
3876  }
3877 
3878  if (vsids_reserved != NULL)
3879  {
3880  /* Deallocate reserved_sectors */
3881  db_private_free (thread_p, vsids_reserved);
3882  }
3883 
3884  return error_code;
3885 }
3886 
3887 /*
3888  * file_table_collect_vsid () - Function callable by file_extdata_apply_funcs. Used to collect sector ID's from file
3889  * tables.
3890  *
3891  * return : NO_ERROR
3892  * thread_p (in) : Thread entry
3893  * item (in) : Item in extensible data (VSID or FILE_PARTIAL_SECTOR which starts with a VSID)
3894  * index_unused (in) : Unused
3895  * stop (out) : Unused
3896  * args (in/out) : VSID collector
3897  */
3898 static int
3899 file_table_collect_vsid (THREAD_ENTRY * thread_p, const void *item, int index_unused, bool * stop, void *args)
3900 {
3901  const VSID *vsid = (VSID *) item;
3902  FILE_VSID_COLLECTOR *collector = (FILE_VSID_COLLECTOR *) args;
3903 
3904  collector->vsids[collector->n_vsids++] = *vsid;
3905 
3906  return NO_ERROR;
3907 }
3908 
3909 /*
3910  * file_table_collect_all_vsids () - collect all sectors from file table
3911  *
3912  * return : error code
3913  * thread_p (in) : thread entry
3914  * page_fhead (in) : file header page
3915  * collector_out (out) : output VSID collector
3916  */
3917 STATIC_INLINE int
3919 {
3920  FILE_HEADER *fhead;
3921  FILE_EXTENSIBLE_DATA *extdata_ftab;
3922  int error_code = NO_ERROR;
3923 
3924  fhead = (FILE_HEADER *) page_fhead;
3925 
3926  collector_out->vsids = (VSID *) db_private_alloc (thread_p, fhead->n_sector_total * sizeof (VSID));
3927  if (collector_out->vsids == NULL)
3928  {
3929  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
3930  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, fhead->n_sector_total * sizeof (VSID));
3931  return error_code;
3932  }
3933  collector_out->n_vsids = 0;
3934 
3935  /* Collect from partial table */
3936  FILE_HEADER_GET_PART_FTAB (fhead, extdata_ftab);
3937  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, NULL, NULL, file_table_collect_vsid, collector_out,
3938  false, NULL, NULL);
3939  if (error_code != NO_ERROR)
3940  {
3941  ASSERT_ERROR ();
3942  db_private_free_and_init (thread_p, collector_out->vsids);
3943  return error_code;
3944  }
3945 
3946  if (!FILE_IS_TEMPORARY (fhead))
3947  {
3948  /* Collect from full table. */
3949  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_ftab);
3950  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, NULL, NULL, file_table_collect_vsid,
3951  collector_out, false, NULL, NULL);
3952  if (error_code != NO_ERROR)
3953  {
3954  ASSERT_ERROR ();
3955  db_private_free_and_init (thread_p, collector_out->vsids);
3956  return error_code;
3957  }
3958  }
3959 
3960  if (collector_out->n_vsids != fhead->n_sector_total)
3961  {
3962  assert_release (false);
3963  db_private_free_and_init (thread_p, collector_out->vsids);
3964  return ER_FAILED;
3965  }
3966 
3967  qsort (collector_out->vsids, fhead->n_sector_total, sizeof (VSID), disk_compare_vsids);
3968 
3969  return NO_ERROR;
3970 }
3971 
3972 /*
3973  * file_sector_map_dealloc () - FILE_EXTDATA_ITEM_FUNC to deallocate user pages
3974  *
3975  * return : error code
3976  * thread_p (in) : thread entry
3977  * data (in) : FILE_PARTIAL_SECTOR * or VSID *
3978  * index (in) : unused
3979  * stop (in) : unused
3980  * args (in) : is_partial
3981  */
3982 static int
3983 file_sector_map_dealloc (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args)
3984 {
3985  bool is_partial = *(bool *) args;
3987  int offset = 0;
3988  VPID vpid;
3989  PAGE_PTR page = NULL;
3990  int error_code = NO_ERROR;
3991 
3992  if (is_partial)
3993  {
3994  partsect = *(FILE_PARTIAL_SECTOR *) data;
3995  }
3996  else
3997  {
3998  partsect.vsid = *(VSID *) data;
3999  }
4000 
4001  vpid.volid = partsect.vsid.volid;
4002  for (offset = 0, vpid.pageid = SECTOR_FIRST_PAGEID (partsect.vsid.sectid); offset < DISK_SECTOR_NPAGES;
4003  offset++, vpid.pageid++)
4004  {
4005  if (is_partial && !file_partsect_is_bit_set (&partsect, offset))
4006  {
4007  /* not allocated */
4008  continue;
4009  }
4010 
4011  page = pgbuf_fix (thread_p, &vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
4012  if (page == NULL)
4013  {
4014  ASSERT_ERROR_AND_SET (error_code);
4015  return error_code;
4016  }
4017 
4018  if (pgbuf_get_page_ptype (thread_p, page) == PAGE_FTAB)
4019  {
4020  /* table page, do not deallocate yet */
4021  pgbuf_unfix_and_init (thread_p, page);
4022  continue;
4023  }
4024  pgbuf_dealloc_page (thread_p, page);
4025  page = NULL;
4026  }
4027 
4028  return NO_ERROR;
4029 }
4030 
4031 /*
4032  * file_destroy () - Destroy file - unreserve all sectors used by file on disk.
4033  *
4034  * return : Error code
4035  * thread_p (in) : Thread entry
4036  * vfid (in) : File identifier
4037  * is_temp (in) : True for temporary, false otherwise. Caller must know. It relevant information before fixing the file
4038  * header page, whe, if not temporary, we need to remove from file tracker.
4039  */
4040 int
4041 file_destroy (THREAD_ENTRY * thread_p, const VFID * vfid, bool is_temp)
4042 {
4043  VPID vpid_fhead;
4044  PAGE_PTR page_fhead = NULL;
4045  FILE_HEADER *fhead = NULL;
4046  FILE_VSID_COLLECTOR vsid_collector;
4047  FILE_FTAB_COLLECTOR ftab_collector;
4048  DB_VOLPURPOSE volpurpose;
4049  bool save_check_interrupt = false;
4050  int error_code = NO_ERROR;
4051 
4052  assert (vfid != NULL && !VFID_ISNULL (vfid));
4053 
4054  vsid_collector.vsids = NULL;
4055 
4056  if (is_temp)
4057  {
4058  /* do not interrupt destroying temporary files. it will leak pages. */
4059  save_check_interrupt = logtb_set_check_interrupt (thread_p, false);
4060  }
4061  else
4062  {
4063  /* permanent files are first removed from tracker */
4064  error_code = file_tracker_unregister (thread_p, vfid);
4065  if (error_code != NO_ERROR)
4066  {
4067  assert_release (false);
4068  goto exit;
4069  }
4070  }
4071 
4072  ftab_collector.partsect_ftab = NULL;
4073 
4074  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
4075  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
4076  if (page_fhead == NULL)
4077  {
4078  assert_release (!is_temp);
4079  error_code = ER_FAILED;
4080  goto exit;
4081  }
4082 
4083  fhead = (FILE_HEADER *) page_fhead;
4084 
4085 #if !defined(NDEBUG)
4087  {
4089  "TDE: file_destroy(): clear tde bit in pflag in all user pages, VFID = %d|%d, # of encrypting (user) pages = %d, tde algorithm = %s\n",
4090  VFID_AS_ARGS (&fhead->self), fhead->n_page_user,
4092  }
4093 #endif /* !NDEBUG */
4094 
4095  assert (is_temp == FILE_IS_TEMPORARY (fhead));
4097 
4098  error_code = file_table_collect_all_vsids (thread_p, page_fhead, &vsid_collector);
4099  if (error_code != NO_ERROR)
4100  {
4101  assert_release (false);
4102  goto exit;
4103  }
4105 
4106  file_log ("file_destroy",
4107  "file %d|%d unreserve %d sectors \n" FILE_HEAD_FULL_MSG,
4108  VFID_AS_ARGS (vfid), fhead->n_sector_total, FILE_HEAD_FULL_AS_ARGS (fhead));
4109 
4110  if (!FILE_IS_TEMPORARY (fhead))
4111  {
4112  /* we need to deallocate pages */
4113  FILE_EXTENSIBLE_DATA *extdata_ftab = NULL;
4114  bool is_partial;
4115  int iter_sects;
4116  int offset;
4117  VPID vpid_ftab;
4118  PAGE_PTR page_ftab = NULL;
4119 
4120  ftab_collector.npages = 0;
4121  ftab_collector.nsects = 0;
4122  ftab_collector.partsect_ftab =
4123  (FILE_PARTIAL_SECTOR *) db_private_alloc (thread_p, fhead->n_page_ftab * sizeof (FILE_PARTIAL_SECTOR));
4124  if (ftab_collector.partsect_ftab == NULL)
4125  {
4127  fhead->n_page_ftab * sizeof (FILE_PARTIAL_SECTOR));
4128  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
4129  goto exit;
4130  }
4131 
4132  FILE_HEADER_GET_PART_FTAB (fhead, extdata_ftab);
4133  is_partial = true;
4134  error_code =
4135  file_extdata_apply_funcs (thread_p, extdata_ftab, file_extdata_collect_ftab_pages, &ftab_collector,
4136  file_sector_map_dealloc, &is_partial, true, NULL, NULL);
4137  if (error_code != NO_ERROR)
4138  {
4139  ASSERT_ERROR ();
4140  goto exit;
4141  }
4142 
4143  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_ftab);
4144  is_partial = false;
4145  error_code =
4146  file_extdata_apply_funcs (thread_p, extdata_ftab, file_extdata_collect_ftab_pages, &ftab_collector,
4147  file_sector_map_dealloc, &is_partial, true, NULL, NULL);
4148  if (error_code != NO_ERROR)
4149  {
4150  ASSERT_ERROR ();
4151  goto exit;
4152  }
4153 
4154  /* deallocate table pages - other than header page */
4155  for (iter_sects = 0; iter_sects < ftab_collector.nsects; iter_sects++)
4156  {
4157  vpid_ftab.volid = ftab_collector.partsect_ftab[iter_sects].vsid.volid;
4158  for (offset = 0,
4159  vpid_ftab.pageid = SECTOR_FIRST_PAGEID (ftab_collector.partsect_ftab[iter_sects].vsid.sectid);
4160  offset < DISK_SECTOR_NPAGES; offset++, vpid_ftab.pageid++)
4161  {
4162  if (file_partsect_is_bit_set (&ftab_collector.partsect_ftab[iter_sects], offset))
4163  {
4164  page_ftab = pgbuf_fix (thread_p, &vpid_ftab, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
4165  if (page_ftab == NULL)
4166  {
4167  ASSERT_ERROR_AND_SET (error_code);
4168  goto exit;
4169  }
4170  pgbuf_dealloc_page (thread_p, page_ftab);
4171  page_ftab = NULL;
4172  }
4173  }
4174  }
4175  /* deallocate header page */
4176  pgbuf_dealloc_page (thread_p, page_fhead);
4177  page_fhead = NULL;
4178  }
4179  else
4180  {
4181  /* todo: invalidate pages in page buffer. actually move them to the bottom of LRU lists. */
4182  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.nfile, -1);
4183  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_ftab, -fhead->n_page_ftab);
4184  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_user, -fhead->n_page_user);
4185  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_reserved, -fhead->n_page_free);
4186  pgbuf_unfix_and_init (thread_p, page_fhead);
4187  }
4188 
4189  /* release occupied sectors on disk */
4190  error_code = disk_unreserve_ordered_sectors (thread_p, volpurpose, vsid_collector.n_vsids, vsid_collector.vsids);
4191  if (error_code != NO_ERROR)
4192  {
4193  assert_release (false);
4194  goto exit;
4195  }
4196 
4197  /* Done */
4198  assert (error_code == NO_ERROR);
4199 
4200 exit:
4201  if (page_fhead != NULL)
4202  {
4203  pgbuf_unfix (thread_p, page_fhead);
4204  }
4205  if (vsid_collector.vsids != NULL)
4206  {
4207  db_private_free (thread_p, vsid_collector.vsids);
4208  }
4209  if (ftab_collector.partsect_ftab != NULL)
4210  {
4211  db_private_free (thread_p, ftab_collector.partsect_ftab);
4212  }
4213  if (is_temp)
4214  {
4215  (void) logtb_set_check_interrupt (thread_p, save_check_interrupt);
4216  }
4217  return error_code;
4218 }
4219 
4220 /*
4221  * file_rv_destroy () - Recovery function used to destroy files.
4222  *
4223  * return : Error code.
4224  * thread_p (in) : Thread entry.
4225  * rcv (in) : Recovery data.
4226  *
4227  * NOTE: This can be used in one of two contexts:
4228  * 1. Logical undo of create file. Should be under a system operation that ends with commit and compensate.
4229  * 2. Run postpone for postponed file destroy. Again, this should be under a system operation, but it should end
4230  * with a commit and run postpone (of course).
4231  */
4232 int
4234 {
4235  VFID *vfid = (VFID *) rcv->data;
4236  int error_code = NO_ERROR;
4237 
4238  assert (sizeof (*vfid) == rcv->length);
4239 
4241 
4242  error_code = file_destroy (thread_p, vfid, false);
4243  if (error_code != NO_ERROR)
4244  {
4245  /* Not acceptable. */
4246  assert_release (false);
4247  return error_code;
4248  }
4249 
4250  return NO_ERROR;
4251 }
4252 
4253 /*
4254  * file_postpone_destroy () - Declare intention of destroying file. File will be destroyed on postpone phase, when the
4255  * transaction commit is confirmed. This is the usual (if not only) way of destroying
4256  * permanent files.
4257  *
4258  * return : Void
4259  * thread_p (in) : Thread entry
4260  * vfid (in) : File identifier
4261  */
4262 void
4263 file_postpone_destroy (THREAD_ENTRY * thread_p, const VFID * vfid)
4264 {
4266 
4267 #if !defined (NDEBUG)
4268  /* This should be used for permanent files! */
4269  {
4270  VPID vpid_fhead;
4271  PAGE_PTR page_fhead;
4272  FILE_HEADER *fhead;
4273 
4274  vpid_fhead.volid = vfid->volid;
4275  vpid_fhead.pageid = vfid->fileid;
4276  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
4277  if (page_fhead == NULL)
4278  {
4279  ASSERT_ERROR ();
4280  return;
4281  }
4282  fhead = (FILE_HEADER *) page_fhead;
4283  assert (!FILE_IS_TEMPORARY (fhead));
4284  pgbuf_unfix_and_init (thread_p, page_fhead);
4285  }
4286 #endif /* !NDEBUG */
4287 
4288  log_append_postpone (thread_p, RVFL_DESTROY, &addr, sizeof (*vfid), vfid);
4289 }
4290 
4291 /*
4292  * file_temp_retire () - retire temporary file (must not be preserved)
4293  *
4294  * return : error code
4295  * thread_p (in) : thread entry
4296  * vfid (in) : file identifier
4297  */
4298 int
4299 file_temp_retire (THREAD_ENTRY * thread_p, const VFID * vfid)
4300 {
4301  return file_temp_retire_internal (thread_p, vfid, false);
4302 }
4303 
4304 /*
4305  * file_temp_retire_preserved () - retire temporary file that was preserved
4306  *
4307  * return : error code
4308  * thread_p (in) : thread entry
4309  * vfid (in) : file identifier
4310  */
4311 int
4313 {
4314  return file_temp_retire_internal (thread_p, vfid, true);
4315 }
4316 
4317 /*
4318  * file_temp_retire_internal () - retire temporary file. put it in cache is possible or destroy the file.
4319  *
4320  * return : error code
4321  * thread_p (in) : thread entry
4322  * vfid (in) : file identifier
4323  * was_preserved (in) : true if entry was preserved in session. it is important to know because we cannot find it in
4324  * transaction list.
4325  */
4326 STATIC_INLINE int
4327 file_temp_retire_internal (THREAD_ENTRY * thread_p, const VFID * vfid, bool was_preserved)
4328 {
4329  FILE_TEMPCACHE_ENTRY *entry = NULL;
4330  int error_code = NO_ERROR;
4331 
4332  if (was_preserved)
4333  {
4335  error_code = file_tempcache_alloc_entry (&entry);
4337  if (error_code != NO_ERROR)
4338  {
4339  assert (false);
4340  }
4341  if (entry != NULL)
4342  {
4343  entry->vfid = *vfid;
4344  /* type will be set later */
4345  }
4346  else
4347  {
4348  assert (false);
4349  }
4350  }
4351  else
4352  {
4353  entry = file_tempcache_pop_tran_file (thread_p, vfid);
4354  assert (entry != NULL);
4355  }
4356 
4357  if (entry != NULL && file_tempcache_put (thread_p, entry))
4358  {
4359  /* cached */
4360  return NO_ERROR;
4361  }
4362 
4363  /* was not cached. destroy */
4364  /* don't allow interrupt to avoid file leak */
4365  error_code = file_destroy (thread_p, vfid, true);
4366  if (error_code != NO_ERROR)
4367  {
4368  /* we should not have errors */
4369  assert_release (false);
4370  }
4371 
4372  if (entry != NULL)
4373  {
4375  }
4376  return error_code;
4377 }
4378 
4379 /*
4380  * file_rv_perm_expand_undo () - Undo permanent file expansion.
4381  *
4382  * return : NO_ERROR
4383  * thread_p (in) : Thread entry
4384  * rcv (in) : Recovery data
4385  */
4386 int
4388 {
4389  PAGE_PTR page_fhead = rcv->pgptr;
4390  FILE_HEADER *fhead;
4391  FILE_EXTENSIBLE_DATA *part_table;
4392  DKNSECTS save_nsects;
4393 
4394  fhead = (FILE_HEADER *) page_fhead;
4395  assert (!FILE_IS_TEMPORARY (fhead));
4396 
4397  /* how is this done:
4398  * when the file was expanded, all newly reserved sectors have been added to partial table in file header, which was
4399  * empty before.
4400  * we will empty it back, and update statistics (sector count and free page count). */
4401 
4402  /* empty partial table */
4403  FILE_HEADER_GET_PART_FTAB (fhead, part_table);
4404  assert (file_extdata_item_count (part_table) == fhead->n_sector_partial);
4405  assert (VPID_ISNULL (&part_table->vpid_next));
4406  part_table->n_items = 0;
4407 
4408  /* update fhead */
4409  assert (fhead->n_page_free == fhead->n_sector_empty * DISK_SECTOR_NPAGES);
4410  fhead->n_page_total -= fhead->n_page_free;
4411  fhead->n_page_free = 0;
4412  fhead->n_sector_total -= fhead->n_sector_empty;
4413  save_nsects = fhead->n_sector_empty;
4414  fhead->n_sector_partial = 0;
4415  fhead->n_sector_empty = 0;
4416 
4417  file_log ("file_rv_perm_expand_undo",
4418  "removed expanded sectors from partial table and file header in file %d|%d, "
4419  "page header %d|%d, lsa %lld|%d, number of sectors %d \n"
4421  PGBUF_PAGE_STATE_ARGS (page_fhead), save_nsects, FILE_HEAD_ALLOC_AS_ARGS (fhead));
4422 
4423  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
4424 
4425  return NO_ERROR;
4426 }
4427 
4428 /*
4429  * file_rv_perm_expand_redo () - Redo permanent file expansion.
4430  *
4431  * return : Error code
4432  * thread_p (in) : Thread entry
4433  * rcv (in) : Recovery data
4434  */
4435 int
4437 {
4438  PAGE_PTR page_fhead = rcv->pgptr;
4439  FILE_HEADER *fhead;
4440  FILE_EXTENSIBLE_DATA *extdata_part_table;
4441  int count_vsids;
4442  VSID *vsids, *vsid_iter;
4443  FILE_PARTIAL_SECTOR partsect;
4444 
4445  /* how is this done:
4446  * file expansion means a number of sectors have been added to partial table in file header, which was empty before.
4447  * recovery data includes the sector ID's of all new sectors.
4448  * append empty sectors to partial table in file header. */
4449 
4450  vsids = (VSID *) rcv->data;
4451  count_vsids = rcv->length / sizeof (VSID);
4452  assert (count_vsids * (int) sizeof (VSID) == rcv->length);
4453 
4454  fhead = (FILE_HEADER *) page_fhead;
4455  assert (!FILE_IS_TEMPORARY (fhead));
4456 
4457  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_table);
4458  assert (file_extdata_is_empty (extdata_part_table));
4459  /* bitmaps will be empty */
4461  for (vsid_iter = vsids; vsid_iter < vsids + count_vsids; vsid_iter++)
4462  {
4463  partsect.vsid = *vsid_iter;
4464  file_extdata_append (extdata_part_table, &partsect);
4465  }
4466 
4467  fhead->n_sector_total += count_vsids;
4468  assert (fhead->n_sector_empty == 0);
4469  fhead->n_sector_empty = count_vsids;
4470  assert (fhead->n_sector_partial == 0);
4471  fhead->n_sector_partial = count_vsids;
4472 
4473  assert (fhead->n_page_free == 0);
4474  fhead->n_page_free = count_vsids * DISK_SECTOR_NPAGES;
4475  fhead->n_page_total += fhead->n_page_free;
4476 
4477  file_log ("file_rv_perm_expand_redo",
4478  "recovery expand in file %d|%d, file header %d|%d, lsa %lld|%d \n"
4479  FILE_HEAD_ALLOC_MSG FILE_EXTDATA_MSG ("partial table after"),
4480  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_STATE_ARGS (page_fhead),
4481  FILE_HEAD_ALLOC_AS_ARGS (fhead), FILE_EXTDATA_AS_ARGS (extdata_part_table));
4482 
4483  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
4484  return NO_ERROR;
4485 }
4486 
4487 /*
4488  * file_perm_expand () - Expand permanent file by reserving new sectors.
4489  *
4490  * return : Error code
4491  * thread_p (in) : Thread entry
4492  * page_fhead (in) : File header page
4493  */
4494 static int
4495 file_perm_expand (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead)
4496 {
4497  FILE_HEADER *fhead = NULL;
4498  int expand_min_size_in_sectors;
4499  int expand_max_size_in_sectors;
4500  int expand_size_in_sectors;
4501  VSID *vsids_reserved = NULL;
4502  VSID *vsid_iter = NULL;
4503  FILE_EXTENSIBLE_DATA *extdata_part_ftab;
4504  FILE_PARTIAL_SECTOR partsect;
4505  bool is_sysop_started = false;
4506  LOG_LSA save_lsa;
4507  int error_code = NO_ERROR;
4508 
4509  /* caller should have started a system operation */
4511 
4512  fhead = (FILE_HEADER *) page_fhead;
4513  assert (!FILE_IS_TEMPORARY (fhead));
4514 
4515  /* compute desired expansion size. we should consider ratio, minimum size and maximum size. also, maximum size cannot
4516  * exceed the capacity of partial table in file header. we want to avoid the headache of allocating file table pages
4517  */
4518  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
4519  expand_min_size_in_sectors = MAX (fhead->tablespace.expand_min_size / DB_SECTORSIZE, 1);
4520  expand_max_size_in_sectors =
4521  MIN (fhead->tablespace.expand_max_size / DB_SECTORSIZE, file_extdata_remaining_capacity (extdata_part_ftab));
4522  assert (expand_min_size_in_sectors <= expand_max_size_in_sectors);
4523 
4524  expand_size_in_sectors = (int) ((float) fhead->n_sector_total * fhead->tablespace.expand_ratio);
4525  expand_size_in_sectors = MAX (expand_size_in_sectors, expand_min_size_in_sectors);
4526  expand_size_in_sectors = MIN (expand_size_in_sectors, expand_max_size_in_sectors);
4527 
4528  file_log ("file_perm_expand",
4529  "expand file %d|%d by %d sectors. \n" FILE_HEAD_ALLOC_MSG FILE_TABLESPACE_MSG,
4530  VFID_AS_ARGS (&fhead->self), expand_size_in_sectors, FILE_HEAD_ALLOC_AS_ARGS (fhead),
4532 
4533  /* allocate a buffer to hold the new sectors */
4534  vsids_reserved = (VSID *) db_private_alloc (thread_p, expand_size_in_sectors * sizeof (VSID));
4535  if (vsids_reserved == NULL)
4536  {
4537  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, expand_size_in_sectors * sizeof (VSID));
4538  return ER_OUT_OF_VIRTUAL_MEMORY;
4539  }
4540 
4541  /* before we start, we need to open a new system operation that gets committed. it is hard to undo file expansion,
4542  * because we would have to search for each VSID we added individually. moreover, it is very likely to need to expand
4543  * the file again. therefore, we should make the expansion permanent. */
4544  log_sysop_start (thread_p);
4545  is_sysop_started = true;
4546 
4547  /* reserve disk sectors */
4548  error_code =
4549  disk_reserve_sectors (thread_p, DB_PERMANENT_DATA_PURPOSE, fhead->volid_last_expand, expand_size_in_sectors,
4550  vsids_reserved);
4551  if (error_code != NO_ERROR)
4552  {
4553  ASSERT_ERROR ();
4554  goto exit;
4555  }
4556 
4557  /* sort VSID's. */
4558  qsort (vsids_reserved, expand_size_in_sectors, sizeof (VSID), disk_compare_vsids);
4559 
4560  /* save in file header partial table. all sectors will be empty */
4562  for (vsid_iter = vsids_reserved; vsid_iter < vsids_reserved + expand_size_in_sectors; vsid_iter++)
4563  {
4564  partsect.vsid = *vsid_iter;
4565  file_extdata_append (extdata_part_ftab, &partsect);
4566  }
4567 
4568  /* update header stats */
4569  fhead->n_sector_total += expand_size_in_sectors;
4570  assert (fhead->n_sector_empty == 0);
4571  fhead->n_sector_empty = expand_size_in_sectors;
4572  assert (fhead->n_sector_partial == 0);
4573  fhead->n_sector_partial = expand_size_in_sectors;
4574 
4575  assert (fhead->n_page_free == 0);
4576  fhead->n_page_free = expand_size_in_sectors * DISK_SECTOR_NPAGES;
4577  fhead->n_page_total += fhead->n_page_free;
4578 
4579  save_lsa = *pgbuf_get_lsa (page_fhead);
4580 
4581  /* file extended successfully. log the change. */
4582  log_append_undoredo_data2 (thread_p, RVFL_EXPAND, NULL, page_fhead, 0, 0,
4583  expand_size_in_sectors * sizeof (VSID), NULL, vsids_reserved);
4584 
4585  file_log ("file_perm_expand",
4586  "expand file %d|%d, page header %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d; "
4587  "first sector %d|%d \n" FILE_HEAD_ALLOC_MSG FILE_EXTDATA_MSG ("partial table"),
4588  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_lsa),
4589  VSID_AS_ARGS (vsids_reserved), FILE_HEAD_ALLOC_AS_ARGS (fhead), FILE_EXTDATA_AS_ARGS (extdata_part_ftab));
4590 
4591  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
4592 
4593 exit:
4594  if (is_sysop_started)
4595  {
4596  if (error_code != NO_ERROR)
4597  {
4598  log_sysop_abort (thread_p);
4599  }
4600  else
4601  {
4602  log_sysop_commit (thread_p);
4603  }
4604  }
4605  if (vsids_reserved != NULL)
4606  {
4607  db_private_free (thread_p, vsids_reserved);
4608  }
4609  return error_code;
4610 }
4611 
4612 /*
4613  * file_table_move_partial_sectors_to_header () - Move partial sectors from first page of partial table to header
4614  * section of partial table
4615  *
4616  * return : error code
4617  * thread_p (in) : thread entry
4618  * page_fhead (in) : file header page
4619  * alloc_type (in) : page allocation type
4620  * vpid_alloc_out (out) : output VPID of page removed from partial table and reused for new allocation
4621  */
4622 static int
4624  VPID * vpid_alloc_out)
4625 {
4626  FILE_HEADER *fhead = NULL;
4627  FILE_EXTENSIBLE_DATA *extdata_part_ftab_head = NULL;
4628  FILE_EXTENSIBLE_DATA *extdata_part_ftab_first = NULL;
4629  PAGE_PTR page_part_ftab_first = NULL;
4630  int n_items_to_move;
4631  LOG_LSA save_lsa;
4632  int error_code = NO_ERROR;
4633 
4634  /* how it works:
4635  * when we have an empty section in header partial table, but we still have partial sectors in other pages, we move
4636  * some or all partial sectors in first page (all are moved if they fit header section).
4637  *
4638  * if all partial sectors in first page have been moved, then first page is removed from partial table. we used to
4639  * deallocate the page, but to solve some strange corner cases (see CBRD-21242), it proved more convenient to reuse
4640  * the page.
4641  */
4642 
4643  fhead = (FILE_HEADER *) page_fhead;
4644  assert (!FILE_IS_TEMPORARY (fhead));
4645 
4646  /* Caller should have checked */
4647  assert (fhead->n_sector_partial > 0);
4648 
4649  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab_head);
4650  if (VPID_ISNULL (&extdata_part_ftab_head->vpid_next))
4651  {
4652  /* caller should have checked and we should not be here */
4653  assert (false);
4654  error_code = ER_FAILED;
4655  goto exit;
4656  }
4657 
4658  /* get first page of partial table */
4659  page_part_ftab_first =
4660  pgbuf_fix (thread_p, &extdata_part_ftab_head->vpid_next, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
4661  if (page_part_ftab_first == NULL)
4662  {
4663  ASSERT_ERROR_AND_SET (error_code);
4664  goto exit;
4665  }
4666 
4667  /* get partial table extensible data in first page and let's see how many items we can move */
4668  extdata_part_ftab_first = (FILE_EXTENSIBLE_DATA *) page_part_ftab_first;
4669 
4670  file_log ("file_table_move_partial_sectors_to_header",
4671  "file %d|%d \n" FILE_EXTDATA_MSG ("header (destination)")
4672  FILE_EXTDATA_MSG ("first page (source)"),
4673  VFID_AS_ARGS (&fhead->self),
4674  FILE_EXTDATA_AS_ARGS (extdata_part_ftab_head), FILE_EXTDATA_AS_ARGS (extdata_part_ftab_first));
4675 
4676  n_items_to_move = file_extdata_item_count (extdata_part_ftab_first);
4677  if (n_items_to_move == 0)
4678  {
4679  /* not expected. */
4680  assert_release (false);
4681  error_code = ER_FAILED;
4682  goto exit;
4683  }
4684 
4685  /* get partial table extensible data in header page */
4686  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab_head);
4687  if (!file_extdata_is_empty (extdata_part_ftab_head))
4688  {
4689  /* we shouldn't be here. release version will still work. */
4690  assert (false);
4691  goto exit;
4692  }
4693  /* we cannot move more than the capacity of extensible data in header page */
4694  n_items_to_move = MIN (n_items_to_move, file_extdata_remaining_capacity (extdata_part_ftab_head));
4695 
4696  /* copy items to header section */
4697  file_extdata_append_array (extdata_part_ftab_head,
4698  file_extdata_start (extdata_part_ftab_first), (INT16) n_items_to_move);
4699  save_lsa = *pgbuf_get_lsa (page_fhead);
4700  /* log changes to extensible data in header page */
4701  file_log_extdata_add (thread_p, extdata_part_ftab_head, page_fhead, 0,
4702  n_items_to_move, file_extdata_start (extdata_part_ftab_first));
4703 
4704  file_log ("file_table_move_partial_sectors_to_header",
4705  "moved %d items from first page to header page file table. \n"
4706  "file %d|%d, header page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d \n"
4707  FILE_EXTDATA_MSG ("header partial table"), n_items_to_move,
4708  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_lsa),
4709  FILE_EXTDATA_AS_ARGS (extdata_part_ftab_head));
4710 
4711  /* now remove from first page. if all items have been moved, we can deallocate first page. */
4712  if (n_items_to_move < file_extdata_item_count (extdata_part_ftab_first))
4713  {
4714  /* Remove copied entries. */
4715  save_lsa = *pgbuf_get_lsa (page_part_ftab_first);
4716  file_log_extdata_remove (thread_p, extdata_part_ftab_first, page_part_ftab_first, 0, n_items_to_move);
4717  file_extdata_remove_at (extdata_part_ftab_first, 0, n_items_to_move);
4718 
4719  file_log ("file_table_move_partial_sectors_to_header",
4720  "removed %d items from first page partial table \n"
4721  "file %d|%d, page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d \n"
4722  FILE_EXTDATA_MSG ("first page partial table"),
4723  n_items_to_move, VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_part_ftab_first, &save_lsa),
4724  FILE_EXTDATA_AS_ARGS (extdata_part_ftab_first));
4725  }
4726  else
4727  {
4728  /* we can remove first page. but do not deallocate it completely. this is called in the context of
4729  * file_perm_alloc, so we can just use this page. output its VPID and file_perm_alloc will know what to do. */
4730  VPID save_next = extdata_part_ftab_head->vpid_next;
4731  file_log_extdata_set_next (thread_p, extdata_part_ftab_head, page_fhead, &extdata_part_ftab_first->vpid_next);
4732  VPID_COPY (&extdata_part_ftab_head->vpid_next, &extdata_part_ftab_first->vpid_next);
4733 
4734  file_log ("file_table_move_partial_sectors_to_header",
4735  "remove first partial table page %d|%d\n", VPID_AS_ARGS (&save_next));
4736 
4737  *vpid_alloc_out = save_next;
4738  /* callers usually expect a "deallocated" page. we need to simulate that.
4739  * note that maybe we can do without really deallocating. a page type update would be enough. this is however the
4740  * safest way to do it, even though not optimal. the case will not affect performance in any benchmark or
4741  * production scenario anyway. */
4742  pgbuf_dealloc_page (thread_p, page_part_ftab_first);
4743  page_part_ftab_first = NULL;
4744 
4745  if (alloc_type == FILE_ALLOC_TABLE_PAGE_FULL_SECTOR)
4746  {
4747  /* special case: file_perm_alloc also initializes & appends the new full table page. */
4748  error_code = file_table_append_full_sector_page (thread_p, page_fhead, vpid_alloc_out);
4749  if (error_code != NO_ERROR)
4750  {
4751  ASSERT_ERROR ();
4752  VPID_SET_NULL (vpid_alloc_out);
4753  goto exit;
4754  }
4755  }
4756  else if (alloc_type == FILE_ALLOC_USER_PAGE)
4757  {
4758  /* we need to update header statistics regarding numbers of table and user pages */
4759  fhead->n_page_ftab--;
4760  fhead->n_page_user++;
4761 
4763  NULL, NULL);
4764  }
4765  }
4766 
4767  /* done */
4768 
4769 exit:
4770  if (page_part_ftab_first != NULL)
4771  {
4772  pgbuf_unfix_and_init (thread_p, page_part_ftab_first);
4773  }
4774 
4775  return error_code;
4776 }
4777 
4778 /*
4779  * file_rv_fhead_convert_ftab_to_user_page () - recovery update header when converting a table page to user page
4780  *
4781  * return : NO_ERROR
4782  * thread_p (in) : thread entry
4783  * rcv (in) : recovery data
4784  */
4785 int
4787 {
4788  FILE_HEADER *fhead = (FILE_HEADER *) rcv->pgptr;
4789 
4790  fhead->n_page_ftab--;
4791  fhead->n_page_user++;
4792 
4793  pgbuf_set_dirty (thread_p, rcv->pgptr, DONT_FREE);
4794 
4795  return NO_ERROR;
4796 }
4797 
4798 /*
4799  * file_rv_fhead_convert_user_to_ftab_page () - recovery update header when converting a user page to table page
4800  *
4801  * return : NO_ERROR
4802  * thread_p (in) : thread entry
4803  * rcv (in) : recovery data
4804  */
4805 int
4807 {
4808  FILE_HEADER *fhead = (FILE_HEADER *) rcv->pgptr;
4809 
4810  fhead->n_page_ftab++;
4811  fhead->n_page_user--;
4812 
4813  pgbuf_set_dirty (thread_p, rcv->pgptr, DONT_FREE);
4814 
4815  return NO_ERROR;
4816 }
4817 
4818 /*
4819  * file_table_append_full_sector_page () - append a new page to full sectors table
4820  *
4821  * return : error code
4822  * thread_p (in) : thread entry
4823  * page_fhead (in) : page file header
4824  * vpid_new (in) : new page VPID
4825  */
4826 static int
4827 file_table_append_full_sector_page (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, const VPID * vpid_new)
4828 {
4829  /* add newly allocated page to full table extdata; this page was requested while adding a new full sector */
4830  PAGE_PTR page_ftab = NULL;
4831  FILE_EXTENSIBLE_DATA *extdata_new_ftab = NULL;
4832  FILE_EXTENSIBLE_DATA *extdata_full_ftab = NULL;
4833  FILE_HEADER *fhead = (FILE_HEADER *) page_fhead;
4834 
4835  int error_code = NO_ERROR;
4836 
4837  /* small optimization: insert the page at the beginning of the list; it will be easier to access
4838  * when adding the following new full sectors;
4839  * extdata_new_ftab->vpid_next = extdata_full_ftab->vpid_next; extdata_full_ftab->vpid_next = new_vpid;
4840  */
4841  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_full_ftab);
4842 
4843  /* fix new table page */
4844  page_ftab = pgbuf_fix (thread_p, vpid_new, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
4845  if (page_ftab == NULL)
4846  {
4847  ASSERT_ERROR_AND_SET (error_code);
4848  return error_code;
4849  }
4850  pgbuf_set_page_ptype (thread_p, page_ftab, PAGE_FTAB);
4851 
4852  /* init new table extensible data */
4853  extdata_new_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
4854  file_extdata_init (sizeof (VSID), DB_PAGESIZE, extdata_new_ftab);
4855  VPID_COPY (&extdata_new_ftab->vpid_next, &extdata_full_ftab->vpid_next);
4856 
4857  pgbuf_log_new_page (thread_p, page_ftab, file_extdata_size (extdata_new_ftab), PAGE_FTAB);
4858  pgbuf_unfix_and_init (thread_p, page_ftab);
4859 
4860  /* Log and link the page in previous table. */
4861  file_log_extdata_set_next (thread_p, extdata_full_ftab, page_fhead, vpid_new);
4862  VPID_COPY (&extdata_full_ftab->vpid_next, vpid_new);
4863 
4864  file_log ("file_table_append_full_sector_page", "%s", "page has been added to full sectors table \n");
4865  return NO_ERROR;
4866 }
4867 
4868 /*
4869  * file_table_add_full_sector () - Add a new sector to full table
4870  *
4871  * return : Error code
4872  * thread_p (in) : Thread entry
4873  * page_fhead (in) : File header page
4874  * vsid (in) : Sector ID
4875  */
4876 static int
4877 file_table_add_full_sector (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, const VSID * vsid)
4878 {
4879  bool found = false;
4880  PAGE_PTR page_ftab = NULL;
4881  FILE_HEADER *fhead = NULL;
4882  FILE_EXTENSIBLE_DATA *extdata_full_ftab;
4883  PAGE_PTR page_extdata = NULL;
4884  LOG_LSA save_lsa;
4885  int error_code = NO_ERROR;
4886  int pos = -1;
4887 
4888  /* how it works:
4889  * add VSID to full table. first we try to find free space in the existing extensible data components. if there is no
4890  * free space, we allocate a new table page and append it to full table.
4891  *
4892  * note: temporary files does not keep a full table. temporary files only keep partial table (and full sectors are
4893  * never moved)
4894  * note: this must be called in the context of a page allocation and should be under a system operation
4895  */
4896 
4897  assert (page_fhead != NULL);
4898  assert (vsid != NULL);
4900 
4901  fhead = (FILE_HEADER *) page_fhead;
4902  assert (!FILE_IS_TEMPORARY (fhead));
4903 
4904  /* get full table in file header */
4905  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_full_ftab);
4906  /* search for full table component with free space */
4907  error_code = file_extdata_find_not_full (thread_p, &extdata_full_ftab, &page_ftab, &found);
4908  if (error_code != NO_ERROR)
4909  {
4910  ASSERT_ERROR ();
4911  goto exit;
4912  }
4913 
4914  if (!found)
4915  {
4916  /* no free space. add a new page to full table. */
4917  VPID vpid_ftab_new = VPID_INITIALIZER;
4918 
4919  /* unfix the last page that remained fixed from file_extdata_find_not_null */
4920  if (page_ftab != NULL)
4921  {
4922  pgbuf_unfix_and_init (thread_p, page_ftab);
4923  }
4924 
4925  error_code = file_perm_alloc (thread_p, page_fhead, FILE_ALLOC_TABLE_PAGE_FULL_SECTOR, &vpid_ftab_new);
4926  if (error_code != NO_ERROR)
4927  {
4928  ASSERT_ERROR ();
4929  goto exit;
4930  }
4931  assert (!VPID_ISNULL (&vpid_ftab_new));
4932 
4933  /* fix newly allocated table page. note that this is an old page, file_perm_alloc already initialized it. */
4934  page_ftab = pgbuf_fix (thread_p, &vpid_ftab_new, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
4935  if (page_ftab == NULL)
4936  {
4937  ASSERT_ERROR_AND_SET (error_code);
4938  goto exit;
4939  }
4940 
4941  /* the new full table component is used */
4942  extdata_full_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
4943  }
4944 
4945  page_extdata = page_ftab != NULL ? page_ftab : page_fhead;
4946 
4947  /* add the new VSID to full table. note that we keep sectors ordered. */
4948  file_extdata_find_ordered (extdata_full_ftab, vsid, disk_compare_vsids, &found, &pos);
4949  if (found)
4950  {
4951  /* ups, duplicate! */
4952  assert_release (false);
4953  error_code = ER_FAILED;
4954  goto exit;
4955  }
4956  file_extdata_insert_at (extdata_full_ftab, pos, 1, vsid);
4957 
4958  /* log the change. */
4959  save_lsa = *pgbuf_get_lsa (page_extdata);
4960  file_log_extdata_add (thread_p, extdata_full_ftab, page_extdata, pos, 1, vsid);
4961 
4962  file_log ("file_table_add_full_sector",
4963  "add sector %d|%d at position %d in file %d|%d, full table page %d|%d, "
4964  "prev_lsa %lld|%d, crt_lsa %lld|%d, \n"
4965  FILE_EXTDATA_MSG ("full table component"),
4966  VSID_AS_ARGS (vsid), pos, VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_extdata, &save_lsa),
4967  FILE_EXTDATA_AS_ARGS (extdata_full_ftab));
4968 
4969  /* done */
4970  assert (error_code == NO_ERROR);
4971 
4972 exit:
4973  if (page_ftab != NULL)
4974  {
4975  pgbuf_unfix (thread_p, page_ftab);
4976  }
4977  return error_code;
4978 }
4979 
4980 /*
4981  * file_rv_dump_vfid_and_vpid () - Dump recovery data when VFID and VPID are logged (used for several cases).
4982  *
4983  * return : Void
4984  * fp (in) : Dump output
4985  * length (in) : Recovery data length
4986  * data (in) : Recovery data
4987  */
4988 void
4989 file_rv_dump_vfid_and_vpid (FILE * fp, int length, void *data)
4990 {
4991  VFID *vfid = NULL;
4992  VPID *vpid = NULL;
4993  char *rcv_data = (char *) data;
4994  int offset = 0;
4995 
4996  vfid = (VFID *) (rcv_data + offset);
4997  offset += sizeof (*vfid);
4998 
4999  vpid = (VPID *) (rcv_data + offset);
5000  offset += sizeof (*vpid);
5001 
5002  assert (offset == length);
5003 
5004  fprintf (fp, "VFID = %d|%d \nVPID = %d|%d.\n", VFID_AS_ARGS (vfid), VPID_AS_ARGS (vpid));
5005 }
5006 
5007 /*
5008  * file_perm_alloc () - Allocate a new page in permament file.
5009  *
5010  * return : Error code
5011  * thread_p (in) : Thread entry
5012  * page_fhead (in) : File header page
5013  * alloc_type (in) : User/table page
5014  * vpid_alloc_out (out) : VPID of allocated page
5015  */
5016 static int
5017 file_perm_alloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, VPID * vpid_alloc_out)
5018 {
5019  FILE_HEADER *fhead = (FILE_HEADER *) page_fhead;
5020  FILE_EXTENSIBLE_DATA *extdata_part_ftab = NULL;
5021  FILE_PARTIAL_SECTOR *partsect;
5022  int offset_to_alloc_bit;
5023  bool was_empty = false;
5024  bool is_full = false;
5025  LOG_LSA save_lsa;
5026  int error_code = NO_ERROR;
5027 
5028  /* how it works:
5029  * the file header (without considering numerable files) is split into two tables: partial table and full table.
5030  * to allocate new pages, the full is not interesting. to do a very fast allocation, we just pick a page in the first
5031  * partial sector.
5032  *
5033  * if there is no partial sector (all sectors are full), we need to expand the file (by calling file_perm_expand).
5034  * new sectors are reserved and we can pick a page from these sectors.
5035  *
5036  * if the partial sector becomes full, we must move it to full table.
5037  *
5038  * note: this is not for temporary files. temporary file allocation is different.
5039  * note: this does not handle user page table for numerable files.
5040  * note: this should always be called under a system operation. the system operation should always be committed before
5041  * file header page is unfixed.
5042  *
5043  * todo: we might consider to do lazy moves to full table. rather than moving the full sector immediately, we let it
5044  * in partial table until something happens (e.g. the section of partial table in file header becomes entirely
5045  * full).
5046  */
5047 
5049  assert (page_fhead != NULL);
5050 
5051  file_log ("file_perm_alloc", "%s", FILE_ALLOC_TYPE_STRING (alloc_type));
5052 
5053  if (fhead->n_page_free == 0)
5054  {
5055  /* no free pages. we need to expand file. */
5056  error_code = file_perm_expand (thread_p, page_fhead);
5057  if (error_code != NO_ERROR)
5058  {
5059  ASSERT_ERROR ();
5060  goto exit;
5061  }
5062  }
5063  assert (fhead->n_page_free > 0);
5064  assert (fhead->n_sector_partial > 0);
5065 
5066  /* get partial table in file header */
5067  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
5068  if (file_extdata_is_empty (extdata_part_ftab))
5069  {
5070  /* we know we have free pages, so we should have partial sectors in other table pages */
5071  error_code = file_table_move_partial_sectors_to_header (thread_p, page_fhead, alloc_type, vpid_alloc_out);
5072  if (error_code != NO_ERROR)
5073  {
5074  ASSERT_ERROR ();
5075  goto exit;
5076  }
5077  if (!VPID_ISNULL (vpid_alloc_out))
5078  {
5079  /* table page has been reused. */
5080  goto exit;
5081  }
5082  }
5083 
5084  /* we must have partial sectors in header! */
5085  assert (!file_extdata_is_empty (extdata_part_ftab));
5086 
5087  /* allocate a new page in first partial sector */
5088  partsect = (FILE_PARTIAL_SECTOR *) file_extdata_start (extdata_part_ftab);
5089 
5090  /* should not be full */
5091  assert (!file_partsect_is_full (partsect));
5092 
5093  /* was partial sector actually empty? we keep this as a statistic for now */
5094  was_empty = file_partsect_is_empty (partsect);
5095 
5096  /* allocate a page in this partial sector */
5097  if (!file_partsect_alloc (partsect, vpid_alloc_out, &offset_to_alloc_bit))
5098  {
5099  /* should not happen, this is a logic error. */
5100  assert_release (false);
5101  error_code = ER_FAILED;
5102  goto exit;
5103  }
5104 
5105  assert (file_partsect_is_bit_set (partsect, offset_to_alloc_bit));
5106  save_lsa = *pgbuf_get_lsa (page_fhead);
5107 
5108  /* log allocation */
5109  log_append_undoredo_data2 (thread_p, RVFL_PARTSECT_ALLOC, NULL, page_fhead,
5110  (PGLENGTH) ((char *) partsect - page_fhead),
5111  sizeof (offset_to_alloc_bit), sizeof (offset_to_alloc_bit),
5112  &offset_to_alloc_bit, &offset_to_alloc_bit);
5113 
5114  file_log ("file_perm_alloc",
5115  "allocated page %d|%d in file %d|%d page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d, "
5116  "set bit at offset %d in partial sector at offset %d \n"
5117  FILE_PARTSECT_MSG ("partsect after"),
5118  VPID_AS_ARGS (vpid_alloc_out), VFID_AS_ARGS (&fhead->self),
5119  PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_lsa), offset_to_alloc_bit,
5120  (PGLENGTH) ((char *) partsect - page_fhead), FILE_PARTSECT_AS_ARGS (partsect));
5121 
5122  if (alloc_type == FILE_ALLOC_TABLE_PAGE_FULL_SECTOR)
5123  {
5124  /* we need to add append page before we have to move yet another sector to full. otherwise we'll loop here. */
5125  error_code = file_table_append_full_sector_page (thread_p, page_fhead, vpid_alloc_out);
5126  if (error_code != NO_ERROR)
5127  {
5128  ASSERT_ERROR ();
5129  goto exit;
5130  }
5131  }
5132 
5133  is_full = file_partsect_is_full (partsect);
5134 
5135  /* update header statistics */
5136  file_header_alloc (fhead, alloc_type, was_empty, is_full);
5137  save_lsa = *pgbuf_get_lsa (page_fhead);
5138  file_log_fhead_alloc (thread_p, page_fhead, alloc_type, was_empty, is_full);
5139 
5140  file_log ("file_perm_alloc",
5141  "update header in file %d|%d, header page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d, "
5142  "after %s, was_empty = %s, is_full = %s, \n" FILE_HEAD_ALLOC_MSG,
5143  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_lsa),
5144  FILE_ALLOC_TYPE_STRING (alloc_type), was_empty ? "true" : "false",
5145  is_full ? "true" : "false", FILE_HEAD_ALLOC_AS_ARGS (fhead));
5146 
5147  /* we need to first update header and then move full partial sector to full table. we might need a new page and we
5148  * must know if no free pages are available to expand the file */
5149  if (is_full)
5150  {
5151  /* move to full table. */
5152  VSID vsid_full;
5153 
5154  assert (file_partsect_is_full (partsect));
5155 
5156  /* save VSID before removing from partial table */
5157  vsid_full = partsect->vsid;
5158 
5159  /* remove from partial table first. adding to full table may need a new page and it expects to find one in first
5160  * partial sector. */
5161  save_lsa = *pgbuf_get_lsa (page_fhead);
5162  file_log_extdata_remove (thread_p, extdata_part_ftab, page_fhead, 0, 1);
5163  file_extdata_remove_at (extdata_part_ftab, 0, 1);
5164 
5165  file_log ("file_perm_alloc",
5166  "removed full partial sector from position 0 in file %d|%d, header page %d|%d, "
5167  "prev_lsa %lld|%d, crt_lsa %lld|%d, \n"
5168  FILE_EXTDATA_MSG ("partial table after alloc"),
5169  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_lsa),
5170  FILE_EXTDATA_AS_ARGS (extdata_part_ftab));
5171 
5172  /* add to full table */
5173  error_code = file_table_add_full_sector (thread_p, page_fhead, &vsid_full);
5174  if (error_code != NO_ERROR)
5175  {
5176  ASSERT_ERROR ();
5177  goto exit;
5178  }
5179  }
5180 
5181  /* done */
5182 
5183  assert (error_code == NO_ERROR);
5184 
5185 exit:
5187 
5188  return error_code;
5189 }
5190 
5191 /*
5192  * file_init_page_type () - initialize new permanent page by setting its type
5193  *
5194  * return : NO_ERROR
5195  * thread_p (in) : thread entry
5196  * page (in) : new page
5197  * args (in) : PAGE_TYPE *
5198  */
5199 int
5200 file_init_page_type (THREAD_ENTRY * thread_p, PAGE_PTR page, void *args)
5201 {
5202  PAGE_TYPE ptype = *(PAGE_TYPE *) args;
5203 
5204  return file_init_page_type_internal (thread_p, page, ptype, false);
5205 }
5206 
5207 /*
5208  * file_init_temp_page_type () - initialize new temporary page by setting its type
5209  *
5210  * return : NO_ERROR
5211  * thread_p (in) : thread entry
5212  * page (in) : new page
5213  * args (in) : PAGE_TYPE *
5214  */
5215 int
5216 file_init_temp_page_type (THREAD_ENTRY * thread_p, PAGE_PTR page, void *args)
5217 {
5218  PAGE_TYPE ptype = *(PAGE_TYPE *) args;
5219 
5220  return file_init_page_type_internal (thread_p, page, ptype, true);
5221 }
5222 
5223 /*
5224  * file_init_page_type_internal () - initialize new page by setting its type
5225  *
5226  * return : NO_ERROR
5227  * thread_p (in) : thread entry
5228  * page (in) : new page
5229  * ptype (in) : page type
5230  * is_temp (in) : true if temporary page, false if permanent
5231  */
5232 STATIC_INLINE int
5233 file_init_page_type_internal (THREAD_ENTRY * thread_p, PAGE_PTR page, PAGE_TYPE ptype, bool is_temp)
5234 {
5235  pgbuf_set_page_ptype (thread_p, page, ptype);
5236  if (!is_temp)
5237  {
5238  log_append_undoredo_data2 (thread_p, RVPGBUF_NEW_PAGE, NULL, page, (PGLENGTH) ptype, 0, 0, NULL, NULL);
5239  }
5240  pgbuf_set_dirty (thread_p, page, DONT_FREE);
5241  return NO_ERROR;
5242 }
5243 
5244 /*
5245  * file_alloc () - Allocate an user page for file.
5246  *
5247  * return : Error code
5248  * thread_p (in) : Thread entry
5249  * vfid (in) : File identifier
5250  * f_init (in) : init page function (must not be NULL for permanent page allocation)
5251  * f_init_args (in) : arguments for init page function
5252  * vpid_out (out) : VPID of page.
5253  * page_out (out) : if not null, it will output newly allocated page.
5254  */
5255 int
5256 file_alloc (THREAD_ENTRY * thread_p, const VFID * vfid, FILE_INIT_PAGE_FUNC f_init, void *f_init_args, VPID * vpid_out,
5257  PAGE_PTR * page_out)
5258 {
5259 #define UNDO_DATA_SIZE (sizeof (VFID) + sizeof (VPID))
5260  VPID vpid_fhead;
5261  PAGE_PTR page_fhead = NULL;
5262  FILE_HEADER *fhead = NULL;
5263  TDE_ALGORITHM tde_algo = TDE_ALGORITHM_NONE;
5264  bool is_sysop_started = false;
5265  char undo_log_data_buf[UNDO_DATA_SIZE + MAX_ALIGNMENT];
5266  char *undo_log_data = PTR_ALIGN (undo_log_data_buf, MAX_ALIGNMENT);
5267  int error_code = NO_ERROR;
5268 
5269  assert (vfid != NULL && !VFID_ISNULL (vfid));
5270  assert (vpid_out != NULL);
5271 
5272  VPID_SET_NULL (vpid_out);
5273  if (page_out != NULL)
5274  {
5275  *page_out = NULL;
5276  }
5277 
5278  /* fix header */
5279  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
5280  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
5281  if (page_fhead == NULL)
5282  {
5283  ASSERT_ERROR_AND_SET (error_code);
5284  return error_code;
5285  }
5286 
5287  fhead = (FILE_HEADER *) page_fhead;
5288  file_header_sanity_check (thread_p, fhead);
5289 
5290  file_log ("file_alloc", "allocate new %s page. \n" FILE_HEAD_ALLOC_MSG,
5292 
5293  if (FILE_IS_TEMPORARY (fhead))
5294  {
5295  /* allocate page */
5296  error_code = file_temp_alloc (thread_p, page_fhead, FILE_ALLOC_USER_PAGE, vpid_out);
5297  if (error_code != NO_ERROR)
5298  {
5299  ASSERT_ERROR ();
5300  goto exit;
5301  }
5302  }
5303  else
5304  {
5305  /* start a nested system operation. we will end it with commit & undo. this must be atomic. */
5306  log_sysop_start_atomic (thread_p);
5307  is_sysop_started = true;
5308 
5309  /* allocate page */
5310  error_code = file_perm_alloc (thread_p, page_fhead, FILE_ALLOC_USER_PAGE, vpid_out);
5311  if (error_code != NO_ERROR)
5312  {
5313  ASSERT_ERROR ();
5314  goto exit;
5315  }
5316 
5317  /* make undo data for system op commit */
5318  VFID_COPY ((VFID *) undo_log_data, vfid);
5319  VPID_COPY ((VPID *) (undo_log_data + sizeof (VFID)), vpid_out);
5320  }
5321 
5322  assert (!VPID_ISNULL (vpid_out));
5323 
5324  if (FILE_IS_NUMERABLE (fhead))
5325  {
5326  /* we also have to add page to user page table */
5327  error_code = file_numerable_add_page (thread_p, page_fhead, vpid_out);
5328  if (error_code != NO_ERROR)
5329  {
5330  ASSERT_ERROR ();
5331  goto exit;
5332  }
5333  }
5334 
5335  if (f_init)
5336  {
5337  /* initialize page */
5338  PAGE_PTR page_alloc = pgbuf_fix (thread_p, vpid_out, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
5339  if (page_alloc == NULL)
5340  {
5341  ASSERT_ERROR_AND_SET (error_code);
5342  goto exit;
5343  }
5344  error_code = f_init (thread_p, page_alloc, f_init_args);
5345  if (error_code != NO_ERROR)
5346  {
5347  ASSERT_ERROR ();
5348  pgbuf_unfix (thread_p, page_alloc);
5349  goto exit;
5350  }
5351 
5352  assert (pgbuf_get_page_ptype (thread_p, page_alloc) != PAGE_UNKNOWN);
5353 
5354  tde_algo = file_get_tde_algorithm_internal (fhead);
5355 
5356 #if !defined (NDEBUG)
5357  {
5358  TDE_ALGORITHM prev_tde_algo = pgbuf_get_tde_algorithm (page_alloc);
5359  if (tde_algo != prev_tde_algo)
5360  {
5362  "TDE: file_alloc(): set tde bit in pflag, VFID = %d|%d, VPID = %d|%d, tde_algorithm of the file = %s, previous tde algorithm of the page = %s\n",
5363  VFID_AS_ARGS (&fhead->self), VPID_AS_ARGS (vpid_out), tde_get_algorithm_name (tde_algo),
5364  tde_get_algorithm_name (prev_tde_algo));
5365  }
5366  }
5367 #endif /* NDEBUG */
5368 
5369  pgbuf_set_tde_algorithm (thread_p, page_alloc, tde_algo, FILE_IS_TEMPORARY (fhead));
5370 
5371  if (page_out != NULL)
5372  {
5373  *page_out = page_alloc;
5374  }
5375  else
5376  {
5377  pgbuf_unfix (thread_p, page_alloc);
5378  }
5379  }
5380  else
5381  {
5382  assert (FILE_IS_TEMPORARY (fhead));
5383  if (page_out != NULL)
5384  {
5385  *page_out = pgbuf_fix (thread_p, vpid_out, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
5386  if (*page_out == NULL)
5387  {
5388  ASSERT_ERROR_AND_SET (error_code);
5389  goto exit;
5390  }
5391  }
5392  }
5393 
5394  /* done */
5395  assert (error_code == NO_ERROR);
5396 
5397 exit:
5398  if (is_sysop_started)
5399  {
5400  if (error_code != NO_ERROR)
5401  {
5402  /* abort system operation. */
5403  log_sysop_abort (thread_p);
5404  }
5405  else
5406  {
5407  /* commit and undo (to deallocate) */
5408  log_sysop_end_logical_undo (thread_p, RVFL_ALLOC, NULL, UNDO_DATA_SIZE, undo_log_data);
5409  }
5410  }
5411 
5412  /* allocation should be completed; check header */
5413  file_header_sanity_check (thread_p, fhead);
5414 
5415  if (error_code != NO_ERROR && page_out != NULL && *page_out != NULL)
5416  {
5417  /* don't leak page. */
5418  pgbuf_unfix_and_init (thread_p, *page_out);
5419  }
5420 
5421  if (page_fhead != NULL)
5422  {
5423  pgbuf_unfix_and_init (thread_p, page_fhead);
5424  }
5425 
5426  return error_code;
5427 #undef UNDO_DATA_SIZE
5428 }
5429 
5430 /*
5431  * file_alloc_multiple () - Allocate multiple pages at once.
5432  *
5433  * return : Error code.
5434  * thread_p (in) : Thread entry.
5435  * vfid (in) : File identifier.
5436  * f_init (in) : New page init function.
5437  * f_init_args (in) : Arguments for init function.
5438  * npages (in) : Number of pages to allocate.
5439  * vpids_out (out) : VPIDS for allocated pages.
5440  */
5441 int
5442 file_alloc_multiple (THREAD_ENTRY * thread_p, const VFID * vfid,
5443  FILE_INIT_PAGE_FUNC f_init, void *f_init_args, int npages, VPID * vpids_out)
5444 {
5445  VPID *vpid_iter;
5446  VPID local_vpid = VPID_INITIALIZER;
5447  int iter;
5448  VPID vpid_fhead;
5449  PAGE_PTR page_fhead = NULL;
5450  FILE_HEADER *fhead = NULL;
5451  bool is_temp;
5452  int error_code = NO_ERROR;
5453 
5454  assert (vfid != NULL && !VFID_ISNULL (vfid));
5455  assert (npages >= 1);
5456 
5457  /* fix header */
5458  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
5459  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
5460  if (page_fhead == NULL)
5461  {
5462  ASSERT_ERROR_AND_SET (error_code);
5463  return error_code;
5464  }
5465 
5466  fhead = (FILE_HEADER *) page_fhead;
5467  file_header_sanity_check (thread_p, fhead);
5468  /* keep header while allocating all pages. we have a great chance to allocate all pages in the same sectors */
5469 
5470  is_temp = FILE_IS_TEMPORARY (fhead);
5471  if (!is_temp)
5472  {
5474 
5475  /* start a system op. we may abort page allocations if an error occurs. */
5476  log_sysop_start (thread_p);
5477  }
5478 
5479  /* do not leak pages! if not numerable, it should use all allocated VPIDS */
5480  assert (FILE_IS_NUMERABLE (fhead) || vpids_out != NULL);
5481 
5482  for (iter = 0; iter < npages; iter++)
5483  {
5484  vpid_iter = vpids_out ? vpids_out + iter : &local_vpid;
5485  error_code = file_alloc (thread_p, vfid, f_init, f_init_args, vpid_iter, NULL);
5486  if (error_code != NO_ERROR)
5487  {
5488  ASSERT_ERROR ();
5489  goto exit;
5490  }
5491  }
5492  /* done */
5493  assert (error_code == NO_ERROR);
5494 
5495 exit:
5496  if (!is_temp)
5497  {
5499  if (error_code == NO_ERROR)
5500  {
5501  /* caller will decide what happens with allocated pages */
5502  log_sysop_attach_to_outer (thread_p);
5503  }
5504  else
5505  {
5506  /* undo allocations */
5507  log_sysop_abort (thread_p);
5508  }
5509  }
5510 
5511  if (page_fhead != NULL)
5512  {
5513  pgbuf_unfix (thread_p, page_fhead);
5514  }
5515 
5516  return error_code;
5517 }
5518 
5519 /*
5520  * file_alloc_sticky_first_page () - Allocate first file page and make it sticky. It is usually used as special headers
5521  * and should never be deallocated.
5522  *
5523  * return : Error code
5524  * thread_p (in) : Thread entry
5525  * vfid (in) : File identifier
5526  * f_init (in) : init page function (must not be NULL for permanent page allocation)
5527  * f_init_args (in) : arguments for init page function
5528  * vpid_out (out) : Allocated page VPID
5529  * page_out (out) : if not null, it will output newly allocated page.
5530  */
5531 int
5532 file_alloc_sticky_first_page (THREAD_ENTRY * thread_p, const VFID * vfid, FILE_INIT_PAGE_FUNC f_init, void *f_init_args,
5533  VPID * vpid_out, PAGE_PTR * page_out)
5534 {
5535  VPID vpid_fhead;
5536  PAGE_PTR page_fhead = NULL;
5537  FILE_HEADER *fhead = NULL;
5538  LOG_LSA save_lsa;
5539  int error_code = NO_ERROR;
5540 
5541  assert (vfid != NULL && !VFID_ISNULL (vfid));
5542  assert (vpid_out != NULL);
5543 
5544  VPID_SET_NULL (vpid_out);
5545  if (page_out != NULL)
5546  {
5547  *page_out = NULL;
5548  }
5549 
5550  /* fix header */
5551  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
5552  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
5553  if (page_fhead == NULL)
5554  {
5555  ASSERT_ERROR_AND_SET (error_code);
5556  return error_code;
5557  }
5558 
5559  fhead = (FILE_HEADER *) page_fhead;
5560  file_header_sanity_check (thread_p, fhead);
5561 
5562  assert (fhead->n_page_user == 0);
5563  assert (VPID_ISNULL (&fhead->vpid_sticky_first));
5564 
5565  error_code = file_alloc (thread_p, vfid, f_init, f_init_args, vpid_out, page_out);
5566  if (error_code != NO_ERROR)
5567  {
5568  ASSERT_ERROR ();
5569  goto exit;
5570  }
5571 
5572  /* save VPID */
5573  save_lsa = *pgbuf_get_lsa (page_fhead);
5575  page_fhead, 0, sizeof (VPID), sizeof (VPID), &fhead->vpid_sticky_first, vpid_out);
5576  fhead->vpid_sticky_first = *vpid_out;
5577  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
5578 
5579  /* done */
5580  file_header_sanity_check (thread_p, fhead);
5581  assert (error_code == NO_ERROR);
5582 
5583  file_log ("file_alloc_sticky_first_page",
5584  "set vpid_sticky_first to %d|%d in file %d|%d, header page %d|%d, "
5585  "prev_lsa %lld|%d, crt_lsa %lld|%d", VPID_AS_ARGS (vpid_out),
5586  VFID_AS_ARGS (vfid), PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_lsa));
5587 
5588 exit:
5589  if (page_fhead != NULL)
5590  {
5591  pgbuf_unfix (thread_p, page_fhead);
5592  }
5593  return error_code;
5594 }
5595 
5596 /*
5597  * file_rv_fhead_sticky_page () - Recovery sticky page VPID in file header.
5598  *
5599  * return : NO_ERROR
5600  * thread_p (in) : Thread entry
5601  * rcv (in) : Recovery data
5602  */
5603 int
5605 {
5606  PAGE_PTR page_fhead = rcv->pgptr;
5607  FILE_HEADER *fhead = (FILE_HEADER *) page_fhead;
5608  VPID *vpid = (VPID *) rcv->data;
5609 
5610  assert (rcv->length == sizeof (*vpid));
5611 
5612  fhead->vpid_sticky_first = *vpid;
5613  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
5614 
5615  file_log ("file_rv_fhead_sticky_page",
5616  "set vpid_sticky_first to %d|%d in file %d|%d, header page %d|%d, lsa %lld|%d",
5617  VPID_AS_ARGS (vpid), VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_STATE_ARGS (page_fhead));
5618  return NO_ERROR;
5619 }
5620 
5621 /*
5622  * file_get_sticky_first_page () - Get VPID of first page. It should be a sticky page.
5623  *
5624  * return : Error code
5625  * thread_p (in) : Thread entry
5626  * vfid (in) : File identifier
5627  * vpid_out (out) : VPID of sticky first page
5628  */
5629 int
5630 file_get_sticky_first_page (THREAD_ENTRY * thread_p, const VFID * vfid, VPID * vpid_out)
5631 {
5632  VPID vpid_fhead;
5633  PAGE_PTR page_fhead = NULL;
5634  FILE_HEADER *fhead = NULL;
5635  int error_code = NO_ERROR;
5636 
5637  /* fix header */
5638  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
5639  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
5640  if (page_fhead == NULL)
5641  {
5642  ASSERT_ERROR_AND_SET (error_code);
5643  return error_code;
5644  }
5645 
5646  fhead = (FILE_HEADER *) page_fhead;
5647  if (LOG_ISRESTARTED ())
5648  {
5649  /* sometimes called before recovery... we cannot guarantee the header is sane at this point. */
5650  file_header_sanity_check (thread_p, fhead);
5651  }
5652 
5653  *vpid_out = fhead->vpid_sticky_first;
5654  if (VPID_ISNULL (vpid_out))
5655  {
5656  assert_release (false);
5657  pgbuf_unfix (thread_p, page_fhead);
5658  return ER_FAILED;
5659  }
5660 
5661  pgbuf_unfix (thread_p, page_fhead);
5662  return NO_ERROR;
5663 }
5664 
5665 /*
5666  * file_set_tde_algorithm () - set encryption algorithm in file header for TDE.
5667  *
5668  * return : NO_ERROR, or ER_code
5669  * thread_p (in) : Thread entry
5670  * vfid (in) : File identifier
5671  * tde_algo (in) : encryption algorithm - NONE, AES, ARIA
5672  *
5673  */
5674 int
5675 file_set_tde_algorithm (THREAD_ENTRY * thread_p, const VFID * vfid, TDE_ALGORITHM tde_algo)
5676 {
5677  VPID vpid_fhead;
5678  PAGE_PTR page_fhead = NULL;
5679  FILE_HEADER *fhead = NULL;
5680  int error_code = NO_ERROR;
5681 
5682  if (!tde_Cipher.is_loaded && tde_algo != TDE_ALGORITHM_NONE)
5683  {
5684  error_code = ER_TDE_CIPHER_IS_NOT_LOADED;
5686  return error_code;
5687  }
5688 
5689  /* fix header */
5690  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
5691  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
5692  if (page_fhead == NULL)
5693  {
5694  ASSERT_ERROR_AND_SET (error_code);
5695  return error_code;
5696  }
5697 
5698  fhead = (FILE_HEADER *) page_fhead;
5699  file_header_sanity_check (thread_p, fhead);
5700 
5701  if (!FILE_IS_TEMPORARY (fhead))
5702  {
5703  TDE_ALGORITHM prev_tde_algo = file_get_tde_algorithm_internal (fhead);
5704  log_append_undoredo_data2 (thread_p, RVFL_FHEAD_SET_TDE_ALGORITHM, NULL, page_fhead, 0, sizeof (TDE_ALGORITHM),
5705  sizeof (TDE_ALGORITHM), &prev_tde_algo, &tde_algo);
5706  }
5707 
5708  file_set_tde_algorithm_internal (fhead, tde_algo);
5709 
5710  pgbuf_set_dirty_and_free (thread_p, page_fhead);
5711 
5712  return NO_ERROR;
5713 }
5714 
5715 /*
5716  * file_rv_set_tde_algorithm () - recovery setting encryption algorithm in file header for TDE.
5717  *
5718  * return : NO_ERROR
5719  * thread_p (in) : Thread entry
5720  * rcv (in) : Recovery data
5721  *
5722  */
5723 int
5725 {
5726  PAGE_PTR page_fhead = rcv->pgptr;
5727  FILE_HEADER *fhead = (FILE_HEADER *) page_fhead;
5728  TDE_ALGORITHM tde_algo = *(TDE_ALGORITHM *) rcv->data;
5729 
5730  assert (rcv->length == sizeof (TDE_ALGORITHM));
5731 
5732  file_set_tde_algorithm_internal (fhead, tde_algo);
5733 
5734  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
5735 
5736  return NO_ERROR;
5737 }
5738 
5739 /*
5740  * file_set_tde_algorithm_internal () - set encryption algorithm in file header for TDE.
5741  *
5742  * fhead (in) : File Header
5743  * tde_algo (in) : encryption algorithm - NONE, AES, ARIA
5744  *
5745  */
5746 void
5748 {
5749  /* clear encrypted flag */
5751 
5752  switch (tde_algo)
5753  {
5754  case TDE_ALGORITHM_AES:
5756  break;
5757  case TDE_ALGORITHM_ARIA:
5759  break;
5760  case TDE_ALGORITHM_NONE:
5761  /* already cleared */
5762  break;
5763  }
5764 
5765 #if !defined(NDEBUG)
5766  er_log_debug (ARG_FILE_LINE, "TDE: file_set_tde_algorithm_internal(): VFID = %d|%d, tde_algorithm = %s\n",
5767  VFID_AS_ARGS (&fhead->self), tde_get_algorithm_name (tde_algo));
5768 #endif /* !NDEBUG */
5769 }
5770 
5771 /*
5772  * file_get_tde_algorithm () - get encryption algorithm in file header for TDE.
5773  *
5774  * return : NO_ERROR
5775  * thread_p (in) : Thread entry
5776  * vfid (in) : File identifier
5777  * fix_head_cond (in): file header page latch condition
5778  * tde_algo (out) : encryption algorithm - NONE, AES, ARIA
5779  *
5780  */
5781 int
5782 file_get_tde_algorithm (THREAD_ENTRY * thread_p, const VFID * vfid, PGBUF_LATCH_CONDITION fix_head_cond,
5783  TDE_ALGORITHM * tde_algo)
5784 {
5785  VPID vpid_fhead;
5786  PAGE_PTR page_fhead = NULL;
5787  FILE_HEADER *fhead = NULL;
5788  int error_code = NO_ERROR;
5789 
5790  /* fix header */
5791  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
5792  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, fix_head_cond);
5793  if (page_fhead == NULL)
5794  {
5795  error_code = ER_FAILED;
5796  return error_code;
5797  }
5798 
5799  fhead = (FILE_HEADER *) page_fhead;
5800 
5801  *tde_algo = file_get_tde_algorithm_internal (fhead);
5802 
5803  pgbuf_unfix (thread_p, page_fhead);
5804 
5805  return NO_ERROR;
5806 }
5807 
5808 /*
5809  * file_get_tde_algorithm_internal () - get encryption algorithm in file header for TDE.
5810  *
5811  * fhead (in) : File Header
5812  * tde_algo (out) : encryption algorithm - NONE, AES, ARIA
5813  *
5814  */
5817 {
5818  // encryption algorithms are exclusive
5820 
5821  if (fhead->file_flags & FILE_FLAG_ENCRYPTED_AES)
5822  {
5823  return TDE_ALGORITHM_AES;
5824  }
5825  else if (fhead->file_flags & FILE_FLAG_ENCRYPTED_ARIA)
5826  {
5827  return TDE_ALGORITHM_ARIA;
5828  }
5829  else
5830  {
5831  return TDE_ALGORITHM_NONE;
5832  }
5833 }
5834 
5835 static int
5836 file_file_map_set_tde_algorithm (THREAD_ENTRY * thread_p, PAGE_PTR * page, bool * stop, void *args)
5837 {
5839  pgbuf_set_tde_algorithm (thread_p, *page, tde_args->tde_algo, tde_args->skip_logging);
5840  return NO_ERROR;
5841 }
5842 
5843 
5844 /*
5845  * file_apply_tde_algorithm () - set encryption algorithm to file and user pages belonging to the file
5846  *
5847  * return : NO_ERROR, or ER_code
5848  * thread_p (in) : Thread entry
5849  * vfid (in) : File identifier
5850  * tde_algo (in) : encryption algorithm - NONE, AES, ARIA
5851  *
5852  * NOTE: The iterating pages part is the same as file_map_pages(). To set TDE to all the pages, unconditional latch has to be latched, but file_map_pages() doesn't support unconditional latch in SERVER_MODE. Becuase this function uses PGBUF_UNCONDITIONAL_LATCH, this has to be called before the file(vfid) is accessed by other thread, or it can cause dead lock (see: file_map_pages()).
5853  *
5854  */
5855 int
5856 file_apply_tde_algorithm (THREAD_ENTRY * thread_p, const VFID * vfid, const TDE_ALGORITHM tde_algo)
5857 {
5858  int error_code = NO_ERROR;
5860  VPID vpid_fhead;
5861  PAGE_PTR page_fhead = NULL;
5862  FILE_HEADER *fhead = NULL;
5863  FILE_EXTENSIBLE_DATA *extdata_ftab;
5864  FILE_MAP_CONTEXT context;
5865  TDE_ALGORITHM prev_tde_algo = TDE_ALGORITHM_NONE;
5866 
5867  assert (vfid != NULL && !VFID_ISNULL (vfid));
5868 
5869  /* fix header */
5870  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
5871  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
5872  if (page_fhead == NULL)
5873  {
5874  ASSERT_ERROR_AND_SET (error_code);
5875  return error_code;
5876  }
5877 
5878  fhead = (FILE_HEADER *) page_fhead;
5879  file_header_sanity_check (thread_p, fhead);
5880 
5881  prev_tde_algo = file_get_tde_algorithm_internal (fhead);
5882 
5883  if (prev_tde_algo == tde_algo)
5884  {
5885  /* it is already applied */
5886  pgbuf_unfix (thread_p, page_fhead);
5887  return NO_ERROR;
5888  }
5889 
5890 #if !defined(NDEBUG)
5892  "TDE: file_apply_tde_algorithm(): VFID = %d|%d, # of encrypting (user) pages = %d, tde algorithm = %s\n",
5893  VFID_AS_ARGS (&fhead->self), fhead->n_page_user, tde_get_algorithm_name (tde_algo));
5894 #endif /* !NDEBUG */
5895 
5896  error_code = file_set_tde_algorithm (thread_p, vfid, tde_algo);
5897  if (error_code != NO_ERROR)
5898  {
5899  pgbuf_unfix (thread_p, page_fhead);
5900  return error_code;
5901  }
5902 
5903  /* init map context */
5904  args.skip_logging = FILE_IS_TEMPORARY (fhead);
5905  args.tde_algo = tde_algo;
5907  context.args = &args;
5909  context.latch_mode = PGBUF_LATCH_WRITE;
5910  context.stop = false;
5911  context.ftab_collector.partsect_ftab = NULL;
5912 
5913  /* collect table pages */
5914  error_code = file_table_collect_ftab_pages (thread_p, page_fhead, true, &context.ftab_collector);
5915  if (error_code != NO_ERROR)
5916  {
5917  goto exit;
5918  }
5919 
5920  /* map over partial sectors table */
5921  FILE_HEADER_GET_PART_FTAB (fhead, extdata_ftab);
5922  context.is_partial = true;
5923  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, NULL, NULL, file_sector_map_pages, &context, false,
5924  NULL, NULL);
5925  if (error_code != NO_ERROR)
5926  {
5927  goto exit;
5928  }
5929 
5930  if (!FILE_IS_TEMPORARY (fhead))
5931  {
5932  /* map over full table */
5933  context.is_partial = false;
5934  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_ftab);
5935  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, NULL, NULL, file_sector_map_pages, &context,
5936  false, NULL, NULL);
5937  if (error_code != NO_ERROR)
5938  {
5939  goto exit;
5940  }
5941  }
5942 
5943  assert (error_code == NO_ERROR);
5944 
5945 exit:
5946  if (page_fhead != NULL)
5947  {
5948  pgbuf_unfix (thread_p, page_fhead);
5949  }
5950  if (context.ftab_collector.partsect_ftab != NULL)
5951  {
5952  db_private_free (thread_p, context.ftab_collector.partsect_ftab);
5953  }
5954 
5955  return error_code;
5956 }
5957 
5958 
5959 /*
5960  * file_dealloc () - Deallocate a file page.
5961  *
5962  * return : Error code
5963  * thread_p (in) : Thread entry
5964  * vfid (in) : File identifier
5965  * vpid (in) : Page identifier
5966  * file_type_hint (in) : Hint for file type. Usually caller knows exactly what kind of file he deallocates the page
5967  * from. Since deallocate is different based on page type (permanent/temporary, numerable),
5968  * and we don't always have to fix header page, it is good to tell dealloc what to do from the
5969  * start.
5970  */
5971 int
5972 file_dealloc (THREAD_ENTRY * thread_p, const VFID * vfid, const VPID * vpid, FILE_TYPE file_type_hint)
5973 {
5974 #define LOG_DATA_SIZE (sizeof (VFID) + sizeof (VPID))
5975  VPID vpid_fhead;
5976  PAGE_PTR page_fhead = NULL;
5977  FILE_HEADER *fhead = NULL;
5978  char log_data_buffer[LOG_DATA_SIZE + MAX_ALIGNMENT];
5979  char *log_data = PTR_ALIGN (log_data_buffer, MAX_ALIGNMENT);
5981  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab = NULL;
5982  PAGE_PTR page_ftab = NULL;
5983  PAGE_PTR page_extdata = NULL;
5984  bool found = false;
5985  int pos = -1;
5986  VPID *vpid_found;
5987  LOG_LSA save_lsa;
5988  int error_code = NO_ERROR;
5989 
5990  /* how it works:
5991  *
5992  * permanent files: we don't actually deallocate page here. we postpone the deallocation after commit, since we don't
5993  * want anyone to reuse it until we are really sure the page is no longer used.
5994  *
5995  * temporary files: we do not deallocate the page.
5996  *
5997  * numerable files: we mark the page for
5998  */
5999 
6000  /* todo: add known is_temp/is_numerable */
6001 
6002  /* read file type from header if caller doesn't know it. debug always reads the type from file header to check caller
6003  * is not wrong. */
6004 #if defined (NDEBUG)
6005  if (file_type_hint == FILE_UNKNOWN_TYPE
6006  || file_type_hint == FILE_EXTENDIBLE_HASH || file_type_hint == FILE_EXTENDIBLE_HASH_DIRECTORY)
6007 #endif /* NDEBUG */
6008  {
6009  /* this should be avoided in release */
6010  vpid_fhead.volid = vfid->volid;
6011  vpid_fhead.pageid = vfid->fileid;
6012 
6013  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
6014  if (page_fhead == NULL)
6015  {
6016  ASSERT_ERROR_AND_SET (error_code);
6017  goto exit;
6018  }
6019  fhead = (FILE_HEADER *) page_fhead;
6020  /* check file type hint is not incorrect.
6021  * note: sometimes the caller may not know if file is FILE_HEAP or FILE_HEAP_REUSE_SLOTS. it doesn't make a
6022  * difference here, so it is accepted to give the generic FILE_HEAP hint. */
6023  assert (file_type_hint == FILE_UNKNOWN_TYPE || file_type_hint == fhead->type
6024  || (file_type_hint == FILE_HEAP && fhead->type == FILE_HEAP_REUSE_SLOTS));
6025  file_type_hint = fhead->type;
6026 
6027  assert (!VPID_EQ (&fhead->vpid_sticky_first, vpid));
6028  }
6029 
6030  if ((fhead != NULL && !FILE_IS_TEMPORARY (fhead)) || file_type_hint != FILE_TEMP)
6031  {
6032  /* for all files, we add a postpone record and do the actual deallocation at run postpone. */
6033  VFID_COPY ((VFID *) log_data, vfid);
6034  VPID_COPY ((VPID *) (log_data + sizeof (VFID)), vpid);
6035  log_append_postpone (thread_p, RVFL_DEALLOC, &log_addr, LOG_DATA_SIZE, log_data);
6036 
6037  file_log ("file_dealloc", "file %s %d|%d dealloc vpid %d|%d postponed",
6038  file_type_to_string (file_type_hint), VFID_AS_ARGS (vfid), VPID_AS_ARGS (vpid));
6039  }
6040  else
6041  {
6042  /* we do not deallocate pages from temporary files */
6043  }
6044 
6045  if (!FILE_TYPE_CAN_BE_NUMERABLE (file_type_hint))
6046  {
6047  /* we don't need to do anything now. the actual deallocation is postponed (or skipped altogether). */
6048  goto exit;
6049  }
6050 
6051  if (page_fhead == NULL)
6052  {
6053  vpid_fhead.volid = vfid->volid;
6054  vpid_fhead.pageid = vfid->fileid;
6055 
6056  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
6057  if (page_fhead == NULL)
6058  {
6059  ASSERT_ERROR_AND_SET (error_code);
6060  goto exit;
6061  }
6062  fhead = (FILE_HEADER *) page_fhead;
6063  }
6064 
6065  assert (page_fhead != NULL);
6066  assert (fhead != NULL);
6067  assert (!VPID_EQ (&fhead->vpid_sticky_first, vpid));
6068 
6069  if (!FILE_IS_NUMERABLE (fhead))
6070  {
6071  /* we don't need to do anything now. the actual deallocation is postponed (or skipped altogether). */
6072  goto exit;
6073  }
6074 
6075  /* search for VPID in user page table */
6076  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
6077  error_code = file_extdata_search_item (thread_p, &extdata_user_page_ftab, vpid, file_compare_vpids, false, true,
6078  &found, &pos, &page_ftab);
6079  if (error_code != NO_ERROR)
6080  {
6081  ASSERT_ERROR ();
6082  goto exit;
6083  }
6084  if (!found)
6085  {
6086  /* not found?? corrupted table! */
6087  assert_release (false);
6088  error_code = ER_FAILED;
6089  goto exit;
6090  }
6091 
6092  /* check not marked as deleted */
6093  vpid_found = (VPID *) file_extdata_at (extdata_user_page_ftab, pos);
6094  if (FILE_USER_PAGE_IS_MARKED_DELETED (vpid_found))
6095  {
6096  /* already marked as deleted? I don't think so! */
6097  assert_release (false);
6098  error_code = ER_FAILED;
6099  goto exit;
6100  }
6101 
6102  /* mark page as deleted */
6103  FILE_USER_PAGE_MARK_DELETED (vpid_found);
6104 
6105  page_extdata = page_ftab != NULL ? page_ftab : page_fhead;
6106  save_lsa = *pgbuf_get_lsa (page_extdata);
6107 
6108  pgbuf_set_dirty (thread_p, page_extdata, DONT_FREE);
6109  if (!FILE_IS_TEMPORARY (fhead))
6110  {
6111  /* log it */
6113 
6114  addr.pgptr = page_extdata;
6115  addr.offset = (PGLENGTH) (((char *) vpid_found) - addr.pgptr);
6116  log_append_undoredo_data (thread_p, RVFL_USER_PAGE_MARK_DELETE, &addr, LOG_DATA_SIZE, 0, log_data, NULL);
6117  }
6118 
6119  file_log ("file_dealloc",
6120  "marked page %d|%d as deleted in file %d|%d, page %d|%d, prev_lsa %lld|%d, "
6121  "crt_lsa %lld_%d, at offset %d ", VPID_AS_ARGS (vpid_found),
6122  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_extdata, &save_lsa),
6123  (PGLENGTH) (((char *) vpid_found) - page_extdata));
6124 
6125  /* update file header */
6126  file_header_update_mark_deleted (thread_p, page_fhead, 1);
6127 
6128  file_log ("file_dealloc", "file %d|%d marked vpid %|%d as deleted", VFID_AS_ARGS (vfid), VPID_AS_ARGS (vpid));
6129 
6130  if (FILE_CACHE_LAST_FIND_NTH (fhead))
6131  {
6132  /* reset cached search location */
6134  fhead->first_index_find_nth_last = 0;
6135  }
6136 
6137  /* done */
6138  assert (error_code != NO_ERROR);
6139 
6140 exit:
6141  if (page_fhead != NULL)
6142  {
6143  pgbuf_unfix (thread_p, page_fhead);
6144  }
6145  if (page_ftab != NULL)
6146  {
6147  pgbuf_unfix (thread_p, page_ftab);
6148  }
6149 
6150  return error_code;
6151 
6152 #undef LOG_DATA_SIZE
6153 }
6154 
6155 /*
6156  * file_perm_dealloc () - Deallocate page from file tables.
6157  *
6158  * return : Error code
6159  * thread_p (in) : Thread entry
6160  * page_fhead (in) : File header page
6161  * vpid_dealloc (in) : VPID of page being deallocated
6162  * alloc_type (in) : User/table page allocation type
6163  */
6164 static int
6165 file_perm_dealloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, const VPID * vpid_dealloc, FILE_ALLOC_TYPE alloc_type)
6166 {
6167  FILE_HEADER *fhead = NULL;
6168  FILE_EXTENSIBLE_DATA *extdata_part_ftab;
6169  FILE_EXTENSIBLE_DATA *extdata_full_ftab;
6170  bool found;
6171  int position;
6172  PAGE_PTR page_ftab = NULL;
6173  VSID vsid_dealloc;
6174  bool is_empty = false;
6175  bool was_full = false;
6177  int offset_to_dealloc_bit;
6178  PAGE_PTR page_dealloc = NULL;
6179  LOG_LSA save_page_lsa;
6180  int error_code = NO_ERROR;
6181 
6182  /* how it works:
6183  * the deallocation should find sector of page and clear the bit of page in sector page bitmap. if the sector was
6184  * full, it should be moved to partial table.
6185  *
6186  * caller should have started a system operation! all table changes should be committed before file header is unfixed.
6187  *
6188  * note: this is only for permanent files. temporary files do not deallocate pages.
6189  * note: this does not handle user page table.
6190  * note: this should always be called under a system operation.
6191  */
6192 
6194 
6195  fhead = (FILE_HEADER *) page_fhead;
6196  assert (!FILE_IS_TEMPORARY (fhead));
6197  assert (!VPID_EQ (&fhead->vpid_sticky_first, vpid_dealloc));
6198 
6199  /* find page sector in one of the partial or full tables */
6200  vsid_dealloc.volid = vpid_dealloc->volid;
6201  vsid_dealloc.sectid = SECTOR_FROM_PAGEID (vpid_dealloc->pageid);
6202 
6203  file_log ("file_perm_dealloc",
6204  "file %d|%d de%s %d|%d (search for VSID %d|%d) \n" FILE_HEAD_ALLOC_MSG,
6205  VFID_AS_ARGS (&fhead->self), FILE_ALLOC_TYPE_STRING (alloc_type), VPID_AS_ARGS (vpid_dealloc),
6206  VSID_AS_ARGS (&vsid_dealloc), FILE_HEAD_ALLOC_AS_ARGS (fhead));
6207 
6208  /* search partial table. */
6209  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
6210  error_code = file_extdata_search_item (thread_p, &extdata_part_ftab, &vsid_dealloc, disk_compare_vsids, true, true,
6211  &found, &position, &page_ftab);
6212  if (error_code != NO_ERROR)
6213  {
6214  ASSERT_ERROR ();
6215  goto exit;
6216  }
6217 
6218  if (found)
6219  {
6220  /* clear the bit for page. */
6221  FILE_PARTIAL_SECTOR *partsect = (FILE_PARTIAL_SECTOR *) file_extdata_at (extdata_part_ftab, position);
6222 
6223  offset_to_dealloc_bit = file_partsect_pageid_to_offset (partsect, vpid_dealloc->pageid);
6224 
6225  file_partsect_clear_bit (partsect, offset_to_dealloc_bit);
6226  is_empty = file_partsect_is_empty (partsect);
6227 
6228  addr.pgptr = page_ftab != NULL ? page_ftab : page_fhead;
6229  addr.offset = (PGLENGTH) (((char *) partsect) - addr.pgptr);
6230  save_page_lsa = *pgbuf_get_lsa (addr.pgptr);
6231 
6233  sizeof (offset_to_dealloc_bit), sizeof (offset_to_dealloc_bit),
6234  &offset_to_dealloc_bit, &offset_to_dealloc_bit);
6235 
6236  pgbuf_set_dirty (thread_p, addr.pgptr, DONT_FREE);
6237 
6238  file_log ("file_perm_dealloc",
6239  "dealloc page %d|%d in file %d|%d page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d, "
6240  "clear bit at offset %d in partsect at offset %d \n"
6241  FILE_PARTSECT_MSG ("partsect after"),
6242  VPID_AS_ARGS (vpid_dealloc), VFID_AS_ARGS (&fhead->self),
6243  PGBUF_PAGE_MODIFY_ARGS (addr.pgptr, &save_page_lsa), offset_to_dealloc_bit,
6244  addr.offset, FILE_PARTSECT_AS_ARGS (partsect));
6245 
6246  if (page_ftab != NULL)
6247  {
6248  pgbuf_unfix_and_init (thread_p, page_ftab);
6249  }
6250  }
6251  else
6252  {
6253  /* not in partial table. */
6254  FILE_PARTIAL_SECTOR partsect_new;
6255  VPID vpid_merged = VPID_INITIALIZER;
6256  bool is_merged_page_from_sector = false;
6257 
6258  assert (page_ftab == NULL);
6259 
6260  /* remove from full table */
6261 
6262  was_full = true;
6263  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_full_ftab);
6264  error_code = file_extdata_find_and_remove_item (thread_p, extdata_full_ftab, page_fhead, &vsid_dealloc,
6265  disk_compare_vsids, true, NULL, &vpid_merged);
6266  if (error_code != NO_ERROR)
6267  {
6268  ASSERT_ERROR ();
6269  goto exit;
6270  }
6271  if (!VPID_ISNULL (&vpid_merged))
6272  {
6273  /* full table page was merged. we need to deallocate the merged page too, unless it belong to the same sector
6274  * as deallocated page. in that case, we only need to remove its bit from the sector we are moving to partial
6275  * table. */
6276  if (VSID_IS_SECTOR_OF_VPID (&vsid_dealloc, &vpid_merged))
6277  {
6278  is_merged_page_from_sector = true;
6279  /* we'll deal with it below */
6280  }
6281  else
6282  {
6283  /* deallocate page. */
6284  error_code = file_perm_dealloc (thread_p, page_fhead, &vpid_merged, FILE_ALLOC_TABLE_PAGE);
6285  if (error_code != NO_ERROR)
6286  {
6287  ASSERT_ERROR ();
6288  return error_code;
6289  }
6290  }
6291  }
6292 
6293  /* add to partial table. */
6294 
6295  /* create the partial sector structure without the bit for page */
6296  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
6297  partsect_new.vsid = vsid_dealloc;
6298  partsect_new.page_bitmap = FILE_FULL_PAGE_BITMAP;
6299  offset_to_dealloc_bit = file_partsect_pageid_to_offset (&partsect_new, vpid_dealloc->pageid);
6300  file_partsect_clear_bit (&partsect_new, offset_to_dealloc_bit);
6301  if (is_merged_page_from_sector)
6302  {
6303  /* we also need to remove merged page from this sector. */
6304  offset_to_dealloc_bit = file_partsect_pageid_to_offset (&partsect_new, vpid_merged.pageid);
6305  file_partsect_clear_bit (&partsect_new, offset_to_dealloc_bit);
6306 
6307  file_log ("file_perm_dealloc",
6308  "merged full table page %d|%d also belongs to sector being moved to partial table \n",
6309  VPID_AS_ARGS (&vpid_merged));
6310 
6311  /* need to update file header */
6312  file_header_dealloc (fhead, FILE_ALLOC_TABLE_PAGE, false, false);
6313  save_page_lsa = *pgbuf_get_lsa (page_fhead);
6314  file_log_fhead_dealloc (thread_p, page_fhead, FILE_ALLOC_TABLE_PAGE, false, false);
6315 
6316  file_log ("file_perm_dealloc",
6317  "update header in file %d|%d, header page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d, "
6318  "after simulating the deallocation of full table page \n" FILE_HEAD_ALLOC_MSG,
6319  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_page_lsa),
6320  FILE_HEAD_ALLOC_AS_ARGS (fhead));
6321 
6322  /* deallocate page */
6323  page_dealloc = pgbuf_fix (thread_p, &vpid_merged, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
6324  if (page_dealloc == NULL)
6325  {
6326  ASSERT_ERROR_AND_SET (error_code);
6327  return error_code;
6328  }
6329 
6330  pgbuf_dealloc_page (thread_p, page_dealloc);
6332  }
6333 
6334  /* find free space */
6335  error_code = file_extdata_find_not_full (thread_p, &extdata_part_ftab, &page_ftab, &found);
6336  if (error_code != NO_ERROR)
6337  {
6338  ASSERT_ERROR ();
6339  goto exit;
6340  }
6341  /* where is extdata_part_ftab? */
6342  addr.pgptr = page_ftab != NULL ? page_ftab : page_fhead;
6343 
6344  if (found)
6345  {
6346  /* found free space in table */
6347 
6348  /* find the correct position for new partial sector to keep the table ordered */
6349  file_extdata_find_ordered (extdata_part_ftab, &vsid_dealloc, disk_compare_vsids, &found, &position);
6350  if (found)
6351  {
6352  /* ups, duplicate! */
6353  assert_release (false);
6354  error_code = ER_FAILED;
6355  goto exit;
6356  }
6357  save_page_lsa = *pgbuf_get_lsa (addr.pgptr);
6358  file_log_extdata_add (thread_p, extdata_part_ftab, addr.pgptr, position, 1, &partsect_new);
6359  file_extdata_insert_at (extdata_part_ftab, position, 1, &partsect_new);
6360 
6361  file_log ("file_perm_dealloc",
6362  "add new partsect at position %d in file %d|%d, page %d|%d, prev_lsa %lld|%d, "
6363  "crt_lsa %lld|%d \n"
6364  FILE_PARTSECT_MSG ("new partial sector")
6365  FILE_EXTDATA_MSG ("partial table component"), position,
6366  VFID_AS_ARGS (&fhead->self),
6367  PGBUF_PAGE_MODIFY_ARGS (addr.pgptr, &save_page_lsa),
6368  FILE_PARTSECT_AS_ARGS (&partsect_new), FILE_EXTDATA_AS_ARGS (extdata_part_ftab));
6369 
6370  if (page_ftab != NULL)
6371  {
6372  pgbuf_unfix_and_init (thread_p, page_ftab);
6373  }
6374  }
6375  else
6376  {
6377  /* no free space in partial table. we need to add a new page. */
6378  VPID vpid_ftab_new = VPID_INITIALIZER;
6379 
6380  error_code = file_perm_alloc (thread_p, page_fhead, FILE_ALLOC_TABLE_PAGE, &vpid_ftab_new);
6381  if (error_code != NO_ERROR)
6382  {
6383  ASSERT_ERROR ();
6384  goto exit;
6385  }
6386  assert (!VPID_ISNULL (&vpid_ftab_new));
6387 
6388  /* set next VPID in last extensible component */
6389  assert (VPID_ISNULL (&extdata_part_ftab->vpid_next));
6390  file_log_extdata_set_next (thread_p, extdata_part_ftab, addr.pgptr, &vpid_ftab_new);
6391  VPID_COPY (&extdata_part_ftab->vpid_next, &vpid_ftab_new);
6392  if (page_ftab != NULL)
6393  {
6394  /* no longer needed */
6395  pgbuf_unfix_and_init (thread_p, page_ftab);
6396  }
6397 
6398  /* fix new table page */
6399  page_ftab = pgbuf_fix (thread_p, &vpid_ftab_new, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
6400  if (page_ftab == NULL)
6401  {
6402  ASSERT_ERROR_AND_SET (error_code);
6403  goto exit;
6404  }
6405  pgbuf_set_page_ptype (thread_p, page_ftab, PAGE_FTAB);
6406 
6407  /* init new extensible data and add new partial sector */
6408  extdata_part_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
6409  file_extdata_init (sizeof (FILE_PARTIAL_SECTOR), DB_PAGESIZE, extdata_part_ftab);
6410  file_extdata_append (extdata_part_ftab, &partsect_new);
6411  pgbuf_log_new_page (thread_p, page_ftab, file_extdata_size (extdata_part_ftab), PAGE_FTAB);
6412 
6413  file_log ("file_perm_dealloc",
6414  "file %d|%d moved to new partial table page %d|%d \n"
6415  FILE_PARTSECT_MSG ("new partial sector")
6416  FILE_EXTDATA_MSG ("partial table component"),
6417  VFID_AS_ARGS (&fhead->self),
6418  VPID_AS_ARGS (&vpid_ftab_new),
6419  FILE_PARTSECT_AS_ARGS (&partsect_new), FILE_EXTDATA_AS_ARGS (extdata_part_ftab));
6420 
6421  pgbuf_unfix_and_init (thread_p, page_ftab);
6422  }
6423  }
6424 
6425  /* we should have freed any other file table pages */
6426  assert (page_ftab == NULL);
6427 
6428  /* almost done. We need to update header statistics */
6429  file_header_dealloc (fhead, alloc_type, is_empty, was_full);
6430  save_page_lsa = *pgbuf_get_lsa (page_fhead);
6431  file_log_fhead_dealloc (thread_p, page_fhead, alloc_type, is_empty, was_full);
6432 
6433  file_log ("file_perm_dealloc",
6434  "update header in file %d|%d, header page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d, "
6435  "after de%s, is_empty = %s, was_full = %s, \n" FILE_HEAD_ALLOC_MSG,
6436  VFID_AS_ARGS (&fhead->self), PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_page_lsa),
6437  FILE_ALLOC_TYPE_STRING (alloc_type), is_empty ? "true" : "false", was_full ? "true" : "false",
6438  FILE_HEAD_ALLOC_AS_ARGS (fhead));
6439 
6440  /* deallocate page */
6441  page_dealloc = pgbuf_fix (thread_p, vpid_dealloc, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
6442  if (page_dealloc == NULL)
6443  {
6444  ASSERT_ERROR_AND_SET (error_code);
6445  goto exit;
6446  }
6447 
6448  pgbuf_dealloc_page (thread_p, page_dealloc);
6450 
6451  /* done */
6452  assert (error_code == NO_ERROR);
6453 
6454 exit:
6455  if (page_ftab != NULL)
6456  {
6457  pgbuf_unfix (thread_p, page_ftab);
6458  }
6459 
6460  return error_code;
6461 }
6462 
6463 /*
6464  * file_rv_dealloc_internal () - Actual deallocation at recovery.
6465  *
6466  * return : Error code
6467  * thread_p (in) : Thread entry
6468  * rcv (in) : Recovery data
6469  * compensate_or_run_postpone (in) : Compensate if this is called for undo, run postpone if this is called for postpone.
6470  */
6471 static int
6472 file_rv_dealloc_internal (THREAD_ENTRY * thread_p, LOG_RCV * rcv, bool compensate_or_run_postpone)
6473 {
6474  VPID vpid_fhead;
6475  PAGE_PTR page_fhead = NULL;
6476  VFID *vfid;
6477  VPID *vpid_dealloc;
6478  int offset = 0;
6479  FILE_HEADER *fhead = NULL;
6480  bool is_sysop_started = false;
6481  int error_code = NO_ERROR;
6482 
6483  /* how it works:
6484  * deallocates a page in either of two contexts:
6485  * 1. undoing a page allocation.
6486  * 2. doing (actual) page deallocation on do postpone phase.
6487  *
6488  * this should clear the page bit in file tables (partial or full) by calling file_perm_dealloc.
6489  * also we remove the VPID from user page table.
6490  */
6491 
6492  /* recovery data: file identifier + page identifier */
6493  vfid = (VFID *) (rcv->data + offset);
6494  offset += sizeof (*vfid);
6495 
6496  vpid_dealloc = (VPID *) (rcv->data + offset);
6497  offset += sizeof (*vpid_dealloc);
6498 
6499  assert (offset == rcv->length);
6500 
6501  /* get file header */
6502  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
6503  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
6504  if (page_fhead == NULL)
6505  {
6506  /* should not be interrupted */
6507  assert_release (false);
6508  return ER_FAILED;
6509  }
6510 
6511  fhead = (FILE_HEADER *) page_fhead;
6512  file_header_sanity_check (thread_p, fhead);
6513 
6514  if (FILE_IS_TEMPORARY (fhead))
6515  {
6516  /* no need to actually deallocate page. should not even be here. */
6517  assert (false);
6518  goto exit;
6519  }
6520 
6521  /* so, we do need a system operation here. the system operation will end, based on context, with commit & compensate
6522  * or with commit & run postpone. */
6523  log_sysop_start_atomic (thread_p);
6524  is_sysop_started = true;
6525 
6526  /* clear page bit by calling file_perm_dealloc */
6527  error_code = file_perm_dealloc (thread_p, page_fhead, vpid_dealloc, FILE_ALLOC_USER_PAGE);
6528  if (error_code != NO_ERROR)
6529  {
6530  /* We cannot allow errors during recovery! */
6531  assert_release (false);
6532  error_code = ER_FAILED;
6533  goto exit;
6534  }
6535 
6536  if (FILE_IS_NUMERABLE (fhead))
6537  {
6538  /* remove VPID from user page table. */
6539  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab;
6540  VPID vpid_removed = VPID_INITIALIZER;
6541  VPID vpid_merged = VPID_INITIALIZER;
6542 
6543  /* remove from user table */
6544  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
6545  error_code = file_extdata_find_and_remove_item (thread_p, extdata_user_page_ftab, page_fhead, vpid_dealloc,
6546  file_compare_vpids, false, &vpid_removed, &vpid_merged);
6547  if (error_code != NO_ERROR)
6548  {
6549  ASSERT_ERROR ();
6550  goto exit;
6551  }
6552 
6553  if (!VPID_ISNULL (&vpid_merged))
6554  {
6555  /* user page table shrank */
6556  error_code = file_perm_dealloc (thread_p, page_fhead, &vpid_merged, FILE_ALLOC_TABLE_PAGE);
6557  if (error_code != NO_ERROR)
6558  {
6559  ASSERT_ERROR ();
6560  goto exit;
6561  }
6562  }
6563 
6564  /* is mark deleted? */
6565  if (FILE_USER_PAGE_IS_MARKED_DELETED (&vpid_removed))
6566  {
6567  /* update file header */
6568  file_header_update_mark_deleted (thread_p, page_fhead, -1);
6569  }
6570  }
6571 
6572  /* done */
6573  assert (error_code == NO_ERROR);
6574 
6575 exit:
6576  /* system operation must be committed before releasing header page. */
6577  if (is_sysop_started)
6578  {
6579  if (error_code != NO_ERROR)
6580  {
6581  log_sysop_abort (thread_p);
6582  }
6583  else
6584  {
6585  if (compensate_or_run_postpone == FILE_RV_DEALLOC_COMPENSATE)
6586  {
6588  }
6589  else
6590  {
6592  }
6593  }
6594  }
6595 
6596  /* deallocation should be completed; check header */
6597  file_header_sanity_check (thread_p, fhead);
6598 
6599  if (page_fhead != NULL)
6600  {
6601  pgbuf_unfix (thread_p, page_fhead);
6602  }
6603  return error_code;
6604 }
6605 
6606 /*
6607  * file_rv_dealloc_on_undo () - Deallocate the page on undo (we need to use compensate on system op commit)
6608  *
6609  * return : Error code
6610  * thread_p (in) : Thread entry
6611  * rcv (in) : Recovery data
6612  */
6613 int
6615 {
6616  file_log ("file_rv_dealloc_on_undo", "lsa = %lld|%d", LSA_AS_ARGS (&rcv->reference_lsa));
6617 
6618  return file_rv_dealloc_internal (thread_p, rcv, FILE_RV_DEALLOC_COMPENSATE);
6619 }
6620 
6621 /*
6622  * file_rv_dealloc_on_postpone () - Deallocate the page on do postpone (we need to use run postpone on system op commit)
6623  *
6624  * return : Error code
6625  * thread_p (in) : Thread entry
6626  * rcv (in) : Recovery data
6627  */
6628 int
6630 {
6631  file_log ("file_rv_dealloc_on_postpone", "lsa = %lld|%d", LSA_AS_ARGS (&rcv->reference_lsa));
6632 
6634 }
6635 
6636 /*
6637  * file_get_num_user_pages () - Output number of user pages in file
6638  *
6639  * return : Error code
6640  * thread_p (in) : Thread entry
6641  * vfid (in) : File identifier
6642  * n_user_pages_out (out) : Output number of user pages
6643  */
6644 int
6645 file_get_num_user_pages (THREAD_ENTRY * thread_p, const VFID * vfid, int *n_user_pages_out)
6646 {
6647  VPID vpid_fhead;
6648  PAGE_PTR page_fhead;
6649  FILE_HEADER *fhead;
6650  int error_code = NO_ERROR;
6651 
6652  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
6653  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
6654  if (page_fhead == NULL)
6655  {
6656  ASSERT_ERROR_AND_SET (error_code);
6657  return error_code;
6658  }
6659 
6660  fhead = (FILE_HEADER *) page_fhead;
6661  file_header_sanity_check (thread_p, fhead);
6662 
6663  *n_user_pages_out = fhead->n_page_user;
6664  pgbuf_unfix (thread_p, page_fhead);
6665 
6666  return NO_ERROR;
6667 }
6668 
6669 /*
6670  * file_check_vpid () - check vpid is one of the file's user pages
6671  *
6672  * return : DISK_INVALID if page does not belong to file, DISK_ERROR for errors and DISK_VALID for successful
6673  * check
6674  * thread_p (in) : thread entry
6675  * vfid (in) : file identifier
6676  * vpid_lookup (in) : checked VPID
6677  */
6679 file_check_vpid (THREAD_ENTRY * thread_p, const VFID * vfid, const VPID * vpid_lookup)
6680 {
6681  VPID vpid_fhead;
6682  PAGE_PTR page_fhead;
6683  FILE_HEADER *fhead;
6684  PAGE_PTR page_ftab = NULL;
6685  VSID vsid_lookup;
6686  bool found;
6687  int pos;
6688  FILE_EXTENSIBLE_DATA *extdata_part_ftab;
6689  FILE_EXTENSIBLE_DATA *extdata_full_ftab;
6690  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab;
6691  DISK_ISVALID isvalid = DISK_VALID;
6692 
6693  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
6694  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
6695  if (page_fhead == NULL)
6696  {
6697  ASSERT_ERROR ();
6698  return DISK_ERROR;
6699  }
6700 
6701  fhead = (FILE_HEADER *) page_fhead;
6702  file_header_sanity_check (thread_p, fhead);
6703 
6704  /* first search the VPID in sector tables: partial, then full. */
6705  VSID_FROM_VPID (&vsid_lookup, vpid_lookup);
6706 
6707  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
6708  if (file_extdata_search_item (thread_p, &extdata_part_ftab, &vsid_lookup, disk_compare_vsids, true, false, &found,
6709  &pos, &page_ftab) != NO_ERROR)
6710  {
6711  ASSERT_ERROR ();
6712  isvalid = DISK_ERROR;
6713  goto exit;
6714  }
6715  if (found)
6716  {
6717  FILE_PARTIAL_SECTOR *partsect;
6718 
6719  partsect = (FILE_PARTIAL_SECTOR *) file_extdata_at (extdata_part_ftab, pos);
6720  if (file_partsect_is_bit_set (partsect, file_partsect_pageid_to_offset (partsect, vpid_lookup->pageid)))
6721  {
6722  /* ok */
6723  /* fall through */
6724  }
6725  else
6726  {
6727  /* not ok */
6728  assert_release (false);
6729  isvalid = DISK_INVALID;
6730  goto exit;
6731  }
6732  }
6733  else
6734  {
6735  /* Search in full table */
6736  if (page_ftab != NULL)
6737  {
6738  pgbuf_unfix_and_init (thread_p, page_ftab);
6739  }
6740  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_full_ftab);
6741  if (file_extdata_search_item (thread_p, &extdata_full_ftab, &vsid_lookup, disk_compare_vsids, true, false,
6742  &found, &pos, &page_ftab) != NO_ERROR)
6743  {
6744  ASSERT_ERROR ();
6745  isvalid = DISK_ERROR;
6746  goto exit;
6747  }
6748  if (!found)
6749  {
6750  /* not ok */
6751  assert_release (false);
6752  isvalid = DISK_INVALID;
6753  goto exit;
6754  }
6755  }
6756  if (page_ftab != NULL)
6757  {
6758  pgbuf_unfix_and_init (thread_p, page_ftab);
6759  }
6760 
6761  if (FILE_IS_NUMERABLE (fhead))
6762  {
6763  /* Search in user page table */
6764  VPID *vpid_in_table;
6765 
6766  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
6767  if (file_extdata_search_item (thread_p, &extdata_user_page_ftab, vpid_lookup, file_compare_vpids, false, false,
6768  &found, &pos, &page_ftab) != NO_ERROR)
6769  {
6770  ASSERT_ERROR ();
6771  isvalid = DISK_ERROR;
6772  goto exit;
6773  }
6774  if (!found)
6775  {
6776  /* not ok */
6777  assert_release (false);
6778  isvalid = DISK_INVALID;
6779  goto exit;
6780  }
6781  /* check not marked as deleted */
6782  vpid_in_table = (VPID *) file_extdata_at (extdata_user_page_ftab, pos);
6783  if (FILE_USER_PAGE_IS_MARKED_DELETED (vpid_in_table))
6784  {
6785  /* not ok */
6786  assert_release (false);
6787  isvalid = DISK_INVALID;
6788  goto exit;
6789  }
6790  /* ok */
6791  }
6792 
6793  /* page is part of file */
6794  assert (isvalid == DISK_VALID);
6795 
6796 exit:
6797  if (page_ftab != NULL)
6798  {
6799  pgbuf_unfix (thread_p, page_ftab);
6800  }
6801  if (page_fhead != NULL)
6802  {
6803  pgbuf_unfix (thread_p, page_fhead);
6804  }
6805  return isvalid;
6806 }
6807 
6808 /*
6809  * file_get_type () - Get file type for VFID.
6810  *
6811  * return : Error code
6812  * thread_p (in) : Thread entry
6813  * vfid (in) : File identifier
6814  * ftype_out (out) : Output file type
6815  */
6816 int
6817 file_get_type (THREAD_ENTRY * thread_p, const VFID * vfid, FILE_TYPE * ftype_out)
6818 {
6819  VPID vpid_fhead;
6820  PAGE_PTR page_fhead = NULL;
6821  FILE_HEADER *fhead = NULL;
6822 
6823  assert (vfid != NULL && !VFID_ISNULL (vfid));
6824  assert (ftype_out != NULL);
6825 
6826  /* read from file header */
6827  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
6828  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
6829  if (page_fhead == NULL)
6830  {
6831  int error_code = NO_ERROR;
6832 
6833  ASSERT_ERROR_AND_SET (error_code);
6834  return error_code;
6835  }
6836 
6837  fhead = (FILE_HEADER *) page_fhead;
6838  file_header_sanity_check (thread_p, fhead);
6839 
6840  *ftype_out = fhead->type;
6841  assert (*ftype_out != FILE_UNKNOWN_TYPE);
6842 
6843  pgbuf_unfix (thread_p, page_fhead);
6844 
6845  return NO_ERROR;
6846 }
6847 
6848 /*
6849  * file_is_temp () - is file temporary?
6850  *
6851  * return : error code
6852  * thread_p (in) : thread entry
6853  * vfid (in) : file identifier
6854  * is_temp (out) : true for temporary, false otherwise
6855  */
6856 int
6857 file_is_temp (THREAD_ENTRY * thread_p, const VFID * vfid, bool * is_temp)
6858 {
6859  VPID vpid_fhead;
6860  PAGE_PTR page_fhead = NULL;
6861  FILE_HEADER *fhead = NULL;
6862 
6863  assert (vfid != NULL && !VFID_ISNULL (vfid));
6864  assert (is_temp != NULL);
6865 
6866  /* read from file header */
6867  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
6868  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
6869  if (page_fhead == NULL)
6870  {
6871  int error_code = NO_ERROR;
6872  ASSERT_ERROR_AND_SET (error_code);
6873  return error_code;
6874  }
6875  fhead = (FILE_HEADER *) page_fhead;
6876  file_header_sanity_check (thread_p, fhead);
6877 
6878  *is_temp = FILE_IS_TEMPORARY (fhead);
6879 
6880  pgbuf_unfix (thread_p, page_fhead);
6881 
6882  return NO_ERROR;
6883 }
6884 
6885 /*
6886  * file_table_collect_ftab_pages () - collect file table pages
6887  *
6888  * return : error code
6889  * thread_p (in) : thread entry
6890  * page_fhead (in) : file header page
6891  * collect_numerable (in) : true to collect also user page table, false otherwise
6892  * collector_out (out) : output collected table pages
6893  */
6894 STATIC_INLINE int
6895 file_table_collect_ftab_pages (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, bool collect_numerable,
6896  FILE_FTAB_COLLECTOR * collector_out)
6897 {
6898  VPID vpid_fhead;
6899  FILE_HEADER *fhead = NULL;
6900  FILE_EXTENSIBLE_DATA *extdata_ftab;
6901  int error_code;
6902 
6903  fhead = (FILE_HEADER *) page_fhead;
6904 
6905  /* init collector */
6906  collector_out->partsect_ftab =
6907  (FILE_PARTIAL_SECTOR *) db_private_alloc (thread_p, sizeof (FILE_PARTIAL_SECTOR) * fhead->n_page_ftab);
6908  if (collector_out->partsect_ftab == NULL)
6909  {
6911  sizeof (FILE_PARTIAL_SECTOR) * fhead->n_page_ftab);
6912  return ER_OUT_OF_VIRTUAL_MEMORY;
6913  }
6914 
6915  /* add page header */
6916  pgbuf_get_vpid (page_fhead, &vpid_fhead);
6917  VSID_FROM_VPID (&collector_out->partsect_ftab[0].vsid, &vpid_fhead);
6918  collector_out->partsect_ftab[0].page_bitmap = FILE_EMPTY_PAGE_BITMAP;
6919  file_partsect_set_bit (&collector_out->partsect_ftab[0],
6920  file_partsect_pageid_to_offset (&collector_out->partsect_ftab[0], vpid_fhead.pageid));
6921  collector_out->nsects = 1;
6922  collector_out->npages = 1;
6923 
6924  file_log ("file_temp_reset_user_pages",
6925  "init collector with page %d|%d \n "
6926  FILE_PARTSECT_MSG ("partsect"), VPID_AS_ARGS (&vpid_fhead),
6927  FILE_PARTSECT_AS_ARGS (collector_out->partsect_ftab));
6928 
6929  /* add other pages in partial sector table */
6930  FILE_HEADER_GET_PART_FTAB (fhead, extdata_ftab);
6931  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, file_extdata_collect_ftab_pages, collector_out, NULL,
6932  NULL, false, NULL, NULL);
6933  if (error_code != NO_ERROR)
6934  {
6935  ASSERT_ERROR ();
6936  db_private_free_and_init (thread_p, collector_out->partsect_ftab);
6937  return error_code;
6938  }
6939 
6940  if (!FILE_IS_TEMPORARY (fhead))
6941  {
6942  /* add other pages from full sector table */
6943  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_ftab);
6944  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, file_extdata_collect_ftab_pages, collector_out,
6945  NULL, NULL, false, NULL, NULL);
6946  if (error_code != NO_ERROR)
6947  {
6948  ASSERT_ERROR ();
6949  db_private_free_and_init (thread_p, collector_out->partsect_ftab);
6950  return error_code;
6951  }
6952  }
6953 
6954  if (collect_numerable && FILE_IS_NUMERABLE (fhead))
6955  {
6956  /* add other pages from user-page table */
6957  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_ftab);
6958  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, file_extdata_collect_ftab_pages, collector_out,
6959  NULL, NULL, false, NULL, NULL);
6960  if (error_code != NO_ERROR)
6961  {
6962  ASSERT_ERROR ();
6963  db_private_free_and_init (thread_p, collector_out->partsect_ftab);
6964  return error_code;
6965  }
6966  }
6967 
6968  return NO_ERROR;
6969 }
6970 
6971 /*
6972  * file_extdata_collect_ftab_pages () - FILE_EXTDATA_FUNC to collect pages used for file table
6973  *
6974  * return : NO_ERROR
6975  * thread_p (in) : thread entry
6976  * extdata (in) : extensible data
6977  * stop (in) : ignored
6978  * args (in/out) : FILE_FTAB_COLLECTOR * - file table page collector
6979  */
6980 static int
6981 file_extdata_collect_ftab_pages (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop, void *args)
6982 {
6983  FILE_FTAB_COLLECTOR *collect = (FILE_FTAB_COLLECTOR *) args;
6984  VSID vsid_this;
6985  int idx_sect = 0;
6986 
6987  if (!VPID_ISNULL (&extdata->vpid_next))
6988  {
6989  VSID_FROM_VPID (&vsid_this, &extdata->vpid_next);
6990 
6991  /* find in collected sectors */
6992  for (idx_sect = 0; idx_sect < collect->nsects; idx_sect++)
6993  {
6994  if (disk_compare_vsids (&vsid_this, &collect->partsect_ftab->vsid) == 0)
6995  {
6996  break;
6997  }
6998  }
6999 
7000  if (idx_sect == collect->nsects)
7001  {
7002  /* not found, append new sector */
7003  collect->partsect_ftab[collect->nsects].vsid = vsid_this;
7005  collect->nsects++;
7006 
7007  file_log ("file_extdata_collect_ftab_pages",
7008  "add new vsid %d|%d, nsects = %d", VSID_AS_ARGS (&vsid_this), collect->nsects);
7009  }
7010  file_partsect_set_bit (&collect->partsect_ftab[idx_sect],
7011  file_partsect_pageid_to_offset (&collect->partsect_ftab[idx_sect],
7012  extdata->vpid_next.pageid));
7013 
7014  file_log ("file_extdata_collect_ftab_pages",
7015  "collect ftab page %d|%d, \n" FILE_PARTSECT_MSG ("partsect"),
7016  VPID_AS_ARGS (&extdata->vpid_next), FILE_PARTSECT_AS_ARGS (&collect->partsect_ftab[idx_sect]));
7017  collect->npages++;
7018  }
7019 
7020  return NO_ERROR;
7021 }
7022 
7023 /*
7024  * file_table_collector_has_page () - check if page is in collected file table pages
7025  *
7026  * return : true if page is file table page, false otherwise
7027  * collector (in) : file table pages collector
7028  * vpid (in) : page id
7029  */
7030 STATIC_INLINE bool
7032 {
7033  int iter;
7034  VSID vsid;
7035 
7036  VSID_FROM_VPID (&vsid, vpid);
7037 
7038  for (iter = 0; iter < collector->nsects; iter++)
7039  {
7040  if (VSID_EQ (&vsid, &collector->partsect_ftab[iter].vsid))
7041  {
7042  return file_partsect_is_bit_set (&collector->partsect_ftab[iter],
7043  file_partsect_pageid_to_offset (&collector->partsect_ftab[iter],
7044  vpid->pageid));
7045  }
7046  }
7047 
7048  return false;
7049 }
7050 
7051 /*
7052  * file_sector_map_pages () - FILE_EXTDATA_ITEM_FUNC used for mapping a function on all user pages
7053  *
7054  * return : error code
7055  * thread_p (in) : thread entry
7056  * data (in) : FILE_PARTIAL_SECTOR or VSID
7057  * index (in) : ignored
7058  * stop (out) : output true when to stop the mapping
7059  * args (in) : map context
7060  */
7061 static int
7062 file_sector_map_pages (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args)
7063 {
7064  FILE_MAP_CONTEXT *context = (FILE_MAP_CONTEXT *) args;
7066  int iter;
7067  VPID vpid;
7068  PAGE_PTR page = NULL;
7069  int error_code = NO_ERROR;
7070 
7071  assert (context != NULL);
7072  assert (context->stop == false);
7073  assert (context->func != NULL);
7074  assert (context->latch_mode == PGBUF_LATCH_WRITE || context->latch_mode == PGBUF_LATCH_READ);
7076 
7077  /* how this works:
7078  * get all allocated pages from sector in file table. data can be either a partial sector (vsid + allocation bitmap)
7079  * or a vsid (full sector - all its pages are allocated).
7080  * for each page, we have to check first it is not a table page. we only want to map the function for user pages.
7081  *
7082  * if the page cannot be fixed conditionally, it is simply skipped. careful when using unconditional latch in server
7083  * mode. there is a risk of dead-latches.
7084  *
7085  * map function can keep the page, but it must set the page pointer to NULL.
7086  */
7087 
7088  /* hack to know this is partial table or full table */
7089  if (context->is_partial)
7090  {
7091  partsect = *(FILE_PARTIAL_SECTOR *) data;
7092  }
7093  else
7094  {
7095  partsect.vsid = *(VSID *) data;
7096  }
7097 
7098  vpid.volid = partsect.vsid.volid;
7099  for (iter = 0, vpid.pageid = SECTOR_FIRST_PAGEID (partsect.vsid.sectid); iter < FILE_ALLOC_BITMAP_NBITS;
7100  iter++, vpid.pageid++)
7101  {
7102  if (context->is_partial && !file_partsect_is_bit_set (&partsect, iter))
7103  {
7104  /* not allocated */
7105  continue;
7106  }
7107 
7108  if (file_table_collector_has_page (&context->ftab_collector, &vpid))
7109  {
7110  /* skip table pages */
7111  continue;
7112  }
7113 
7114  page = pgbuf_fix (thread_p, &vpid, OLD_PAGE, context->latch_mode, context->latch_cond);
7115  if (page == NULL)
7116  {
7117  if (context->latch_cond == PGBUF_CONDITIONAL_LATCH)
7118  {
7119  /* exit gracefully */
7120  return NO_ERROR;
7121  }
7122  /* error */
7123  ASSERT_ERROR_AND_SET (error_code);
7124  return error_code;
7125  }
7126 
7127  assert (pgbuf_get_page_ptype (thread_p, page) != PAGE_FTAB);
7128 
7129  /* call map function */
7130  error_code = context->func (thread_p, &page, stop, context->args);
7131  if (page != NULL)
7132  {
7133  pgbuf_unfix_and_init (thread_p, page);
7134  }
7135  if (error_code != NO_ERROR)
7136  {
7137  ASSERT_ERROR ();
7138  return error_code;
7139  }
7140 
7141  if (*stop)
7142  {
7143  /* early out */
7144  context->stop = true;
7145  return NO_ERROR;
7146  }
7147  }
7148 
7149  return NO_ERROR;
7150 }
7151 
7152 /*
7153  * file_map_pages () - map given function on all user pages
7154  *
7155  * return : error code
7156  * thread_p (in) : thread entry
7157  * vfid (in) : file identifier
7158  * latch_mode (in) : latch mode
7159  * latch_cond (in) : latch condition
7160  * func (in) : map function
7161  * args (in) : map function arguments
7162  */
7163 int
7164 file_map_pages (THREAD_ENTRY * thread_p, const VFID * vfid, PGBUF_LATCH_MODE latch_mode,
7165  PGBUF_LATCH_CONDITION latch_cond, FILE_MAP_PAGE_FUNC func, void *args)
7166 {
7167  VPID vpid_fhead;
7168  PAGE_PTR page_fhead = NULL;
7169  FILE_HEADER *fhead = NULL;
7170  FILE_EXTENSIBLE_DATA *extdata_ftab;
7171  FILE_MAP_CONTEXT context;
7172  int error_code = NO_ERROR;
7173 
7174  assert (vfid != NULL && !VFID_ISNULL (vfid));
7175  assert (latch_mode == PGBUF_LATCH_READ || latch_mode == PGBUF_LATCH_WRITE);
7176  assert (func != NULL);
7177 
7178  /* how it works:
7179  * get all user pages in partial sector table and full sector table and apply function. the file_sector_map_pages
7180  * is first mapped on entries of partial table and then on full table.
7181  *
7182  * note that file header is read-latched during the whole time. this means page allocations/deallocations are blocked
7183  * during the process. careful when using the function in server-mode. it is not advisable to be used for hot and
7184  * large files.
7185  *
7186  * function must be mapped on user pages only. as a first step we have to collect file table pages. while mapping
7187  * function on pages, these are skipped.
7188  */
7189 
7190 #if defined (SERVER_MODE)
7191  /* we cannot use unconditional latch. allocations can sometimes keep latch on a file page and then try to lock
7192  * header/table. we may cause dead latch.
7193  */
7194  assert (latch_cond == PGBUF_CONDITIONAL_LATCH);
7195  latch_cond = PGBUF_CONDITIONAL_LATCH;
7196 #endif /* SERVER_MODE */
7197 
7198  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
7199  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
7200  if (page_fhead == NULL)
7201  {
7202  ASSERT_ERROR_AND_SET (error_code);
7203  return error_code;
7204  }
7205  fhead = (FILE_HEADER *) page_fhead;
7206  file_header_sanity_check (thread_p, fhead);
7207 
7208  /* init map context */
7209  context.func = func;
7210  context.args = args;
7211  context.latch_cond = latch_cond;
7212  context.latch_mode = latch_mode;
7213  context.stop = false;
7214  context.ftab_collector.partsect_ftab = NULL;
7215 
7216  /* collect table pages */
7217  error_code = file_table_collect_ftab_pages (thread_p, page_fhead, true, &context.ftab_collector);
7218  if (error_code != NO_ERROR)
7219  {
7220  ASSERT_ERROR ();
7221  goto exit;
7222  }
7223 
7224  /* map over partial sectors table */
7225  FILE_HEADER_GET_PART_FTAB (fhead, extdata_ftab);
7226  context.is_partial = true;
7227  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, NULL, NULL, file_sector_map_pages, &context, false,
7228  NULL, NULL);
7229  if (error_code != NO_ERROR)
7230  {
7231  ASSERT_ERROR ();
7232  goto exit;
7233  }
7234  if (context.stop)
7235  {
7236  goto exit;
7237  }
7238 
7239  if (!FILE_IS_TEMPORARY (fhead))
7240  {
7241  /* map over full table */
7242  context.is_partial = false;
7243  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_ftab);
7244  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, NULL, NULL, file_sector_map_pages, &context,
7245  false, NULL, NULL);
7246  if (error_code != NO_ERROR)
7247  {
7248  ASSERT_ERROR ();
7249  goto exit;
7250  }
7251  }
7252 
7253  assert (error_code == NO_ERROR);
7254 
7255 exit:
7256  if (page_fhead != NULL)
7257  {
7258  pgbuf_unfix (thread_p, page_fhead);
7259  }
7260  if (context.ftab_collector.partsect_ftab != NULL)
7261  {
7262  db_private_free (thread_p, context.ftab_collector.partsect_ftab);
7263  }
7264 
7265  return error_code;
7266 }
7267 
7268 /*
7269  * file_table_check () - check file table is valid
7270  *
7271  * return : DISK_INVALID for unexpected errors, DISK_ERROR for expected errors,
7272  * DISK_VALID for successful check
7273  * thread_p (in) : thread entry
7274  * vfid (in) : file identifier
7275  * disk_map_clone (in/out) : clone of disk sector table maps used in stand-alone mode only to cross-check reserved
7276  * sectors
7277  */
7278 static DISK_ISVALID
7279 file_table_check (THREAD_ENTRY * thread_p, const VFID * vfid, DISK_VOLMAP_CLONE * disk_map_clone)
7280 {
7281  VPID vpid_fhead;
7282  PAGE_PTR page_fhead = NULL;
7283  FILE_HEADER *fhead = NULL;
7284  FILE_VSID_COLLECTOR collector;
7285 #if defined (SA_MODE)
7286  int iter_vsid;
7287 #endif /* SA_MODE */
7288 
7289  DISK_ISVALID valid = DISK_VALID;
7290  DISK_ISVALID allvalid = DISK_VALID;
7291  int error_code = NO_ERROR;
7292 
7293 #if defined (SA_MODE)
7294  assert (disk_map_clone != NULL);
7295 #endif /* SA_MODE */
7296 
7297  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
7298  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
7299  if (page_fhead == NULL)
7300  {
7301  ASSERT_ERROR ();
7302  return DISK_ERROR;
7303  }
7304  fhead = (FILE_HEADER *) page_fhead;
7305  file_header_sanity_check (thread_p, fhead);
7306 
7307  error_code = file_table_collect_all_vsids (thread_p, page_fhead, &collector);
7308  if (error_code != NO_ERROR)
7309  {
7310  ASSERT_ERROR ();
7311  goto exit;
7312  }
7313 
7314  if (FILE_IS_NUMERABLE (fhead))
7315  {
7316  /* check all pages in user table belong to collected page */
7317  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab;
7318 
7319  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
7320  error_code = file_extdata_apply_funcs (thread_p, extdata_user_page_ftab, NULL, NULL,
7321  file_table_check_page_is_in_sectors, &collector, false, NULL, NULL);
7322  if (error_code == ER_FAILED)
7323  {
7324  /* set for unexpected cases */
7325  allvalid = DISK_INVALID;
7326  /* fall through: also check sectors are reserved */
7327  }
7328  else if (error_code != NO_ERROR)
7329  {
7330  ASSERT_ERROR ();
7331  goto exit;
7332  }
7333  }
7334 
7335  /* check all sectors are reserved. if the file is very big, this can take a while. don't keep header page fixed */
7336  pgbuf_unfix_and_init (thread_p, page_fhead);
7337 
7338 #if defined (SERVER_MODE)
7339  valid = disk_check_sectors_are_reserved (thread_p, collector.vsids, collector.n_vsids);
7340  if (valid != DISK_VALID && allvalid == DISK_VALID)
7341  {
7342  allvalid = valid;
7343  }
7344 #else /* !SERVER_MODE */ /* SA_MODE */
7345  for (iter_vsid = 0; iter_vsid < collector.n_vsids; iter_vsid++)
7346  {
7347  valid = disk_map_clone_clear (&collector.vsids[iter_vsid], disk_map_clone);
7348  if (valid == DISK_INVALID)
7349  {
7350  allvalid = DISK_INVALID;
7351  }
7352  else
7353  {
7354  assert (valid == DISK_VALID);
7355  }
7356  }
7357 #endif /* SA_MODE */
7358 
7359 exit:
7360  if (page_fhead != NULL)
7361  {
7362  pgbuf_unfix (thread_p, page_fhead);
7363  }
7364 
7365  if (error_code != NO_ERROR && allvalid == DISK_VALID)
7366  {
7367  allvalid = DISK_ERROR;
7368  }
7369 
7370  if (collector.vsids != NULL)
7371  {
7372  db_private_free (thread_p, collector.vsids);
7373  }
7374  return allvalid;
7375 }
7376 
7377 /*
7378  * file_dump () - file dump
7379  *
7380  * return : error code
7381  * thread_p (in) : thread entry
7382  * vfid (in) : file identifier
7383  * fp (in) : output file
7384  */
7385 int
7386 file_dump (THREAD_ENTRY * thread_p, const VFID * vfid, FILE * fp)
7387 {
7388  VPID vpid_fhead;
7389  PAGE_PTR page_fhead = NULL;
7390  FILE_HEADER *fhead = NULL;
7391  int error_code = NO_ERROR;
7392 
7393  fprintf (fp, "\n\n Dumping file %d|%d \n", VFID_AS_ARGS (vfid));
7394 
7395  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
7396  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
7397  if (page_fhead == NULL)
7398  {
7399  ASSERT_ERROR_AND_SET (error_code);
7400  return error_code;
7401  }
7402  fhead = (FILE_HEADER *) page_fhead;
7403 
7404  file_header_dump (thread_p, fhead, fp);
7405 
7406  error_code = file_table_dump (thread_p, fhead, fp);
7407  if (error_code != NO_ERROR)
7408  {
7409  ASSERT_ERROR ();
7410  pgbuf_unfix (thread_p, page_fhead);
7411  return error_code;
7412  }
7413 
7414  pgbuf_unfix (thread_p, page_fhead);
7415  return NO_ERROR;
7416 }
7417 
7418 /*
7419  * file_table_dump () - dump file table
7420  *
7421  * return : error code
7422  * thread_p (in) : thread entry
7423  * fhead (in) : file header
7424  * fp (in) : output file
7425  */
7426 STATIC_INLINE int
7427 file_table_dump (THREAD_ENTRY * thread_p, const FILE_HEADER * fhead, FILE * fp)
7428 {
7429  int error_code = NO_ERROR;
7430  FILE_EXTENSIBLE_DATA *extdata_ftab = NULL;
7431 
7432  fprintf (fp, "FILE TABLE: \n");
7433  FILE_HEADER_GET_PART_FTAB (fhead, extdata_ftab);
7434  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, file_partial_table_extdata_dump, fp,
7435  file_partial_table_item_dump, fp, false, NULL, NULL);
7436  if (error_code != NO_ERROR)
7437  {
7438  ASSERT_ERROR ();
7439  return error_code;
7440  }
7441 
7442  if (!FILE_IS_TEMPORARY (fhead))
7443  {
7444  FILE_HEADER_GET_FULL_FTAB (fhead, extdata_ftab);
7445  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, file_full_table_extdata_dump, fp,
7446  file_full_table_item_dump, fp, false, NULL, NULL);
7447  if (error_code != NO_ERROR)
7448  {
7449  ASSERT_ERROR ();
7450  return error_code;
7451  }
7452  }
7453 
7454  if (FILE_IS_NUMERABLE (fhead))
7455  {
7456  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_ftab);
7457  error_code = file_extdata_apply_funcs (thread_p, extdata_ftab, file_full_table_extdata_dump, fp,
7458  file_full_table_item_dump, fp, false, NULL, NULL);
7459  if (error_code != NO_ERROR)
7460  {
7461  ASSERT_ERROR ();
7462  return error_code;
7463  }
7464  }
7465 
7466  return NO_ERROR;
7467 }
7468 
7469 /*
7470  * file_partial_table_extdata_dump () - dump an extensible data from partial table
7471  *
7472  * return : NO_ERROR
7473  * thread_p (in) : thread entry
7474  * extdata (in) : extensible data
7475  * stop (in) : not used
7476  * args (in) : FILE *
7477  */
7478 static int
7479 file_partial_table_extdata_dump (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop, void *args)
7480 {
7481  FILE *fp = (FILE *) args;
7482 
7483  fprintf (fp, FILE_EXTDATA_MSG ("partial table component"), FILE_EXTDATA_AS_ARGS (extdata));
7484  return NO_ERROR;
7485 }
7486 
7487 /*
7488  * file_partial_table_item_dump () - dump an item from partial table
7489  *
7490  * return : NO_ERROR
7491  * thread_p (in) : thread entry
7492  * data (in) : FILE_PARTIAL_SECTOR *
7493  * index (in) : item index
7494  * stop (in) : not used
7495  * args (in) : FILE *
7496  */
7497 static int
7498 file_partial_table_item_dump (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args)
7499 {
7500  FILE *fp = (FILE *) args;
7501  FILE_PARTIAL_SECTOR *partsect;
7502  int iter;
7503  int line_count;
7504  VPID vpid;
7505 
7506  partsect = (FILE_PARTIAL_SECTOR *) data;
7507  fprintf (fp, FILE_PARTSECT_MSG ("partially allocated sector"), FILE_PARTSECT_AS_ARGS (partsect));
7508 
7509  vpid.volid = partsect->vsid.volid;
7510  fprintf (fp, "\t\t allocated pages:");
7511  line_count = 0;
7512  for (iter = 0, vpid.pageid = SECTOR_FIRST_PAGEID (partsect->vsid.sectid); iter < DISK_SECTOR_NPAGES;
7513  iter++, vpid.pageid++)
7514  {
7515  if (file_partsect_is_bit_set (partsect, iter))
7516  {
7517  if (line_count++ % 8 == 0)
7518  {
7519  fprintf (fp, "\n\t\t\t");
7520  }
7521  fprintf (fp, "%5d|%10d ", VPID_AS_ARGS (&vpid));
7522  }
7523  }
7524 
7525  fprintf (fp, "\n\t\t reserved pages:");
7526  line_count = 0;
7527  for (iter = 0, vpid.pageid = SECTOR_FIRST_PAGEID (partsect->vsid.sectid); iter < DISK_SECTOR_NPAGES;
7528  iter++, vpid.pageid++)
7529  {
7530  if (!file_partsect_is_bit_set (partsect, iter))
7531  {
7532  if (line_count++ % 8 == 0)
7533  {
7534  fprintf (fp, "\n\t\t\t");
7535  }
7536  fprintf (fp, "%5d|%10d ", VPID_AS_ARGS (&vpid));
7537  }
7538  }
7539  fprintf (fp, "\n");
7540 
7541  return NO_ERROR;
7542 }
7543 
7544 /*
7545  * file_full_table_extdata_dump () - dump an extensible data from full table
7546  *
7547  * return : NO_ERROR
7548  * thread_p (in) : thread entry
7549  * extdata (in) : extensible data
7550  * stop (in) : not used
7551  * args (in) : FILE *
7552  */
7553 static int
7554 file_full_table_extdata_dump (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop, void *args)
7555 {
7556  FILE *fp = (FILE *) args;
7557 
7558  fprintf (fp, FILE_EXTDATA_MSG ("full table component"), FILE_EXTDATA_AS_ARGS (extdata));
7559  return NO_ERROR;
7560 }
7561 
7562 /*
7563  * file_full_table_item_dump () - dump an item from full table
7564  *
7565  * return : NO_ERROR
7566  * thread_p (in) : thread entry
7567  * data (in) : VSID *
7568  * index (in) : item index
7569  * stop (in) : not used
7570  * args (in) : FILE *
7571  */
7572 static int
7573 file_full_table_item_dump (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args)
7574 {
7575  FILE *fp = (FILE *) args;
7576  VSID *vsid;
7577  int iter;
7578  int line_count;
7579  VPID vpid;
7580 
7581  vsid = (VSID *) data;
7582  fprintf (fp, "fully allocated sector: vsid = %d|%d \n", VSID_AS_ARGS (vsid));
7583 
7584  line_count = 0;
7585  vpid.volid = vsid->volid;
7586  for (iter = 0, vpid.pageid = SECTOR_FIRST_PAGEID (vsid->sectid); iter < DISK_SECTOR_NPAGES; iter++, vpid.pageid++)
7587  {
7588  if (line_count++ % 8 == 0)
7589  {
7590  fprintf (fp, "\n\t\t\t");
7591  }
7592  fprintf (fp, "%5d|%10d ", VPID_AS_ARGS (&vpid));
7593  }
7594  return NO_ERROR;
7595 }
7596 
7597 /*
7598  * file_user_page_table_extdata_dump () - dump an extensible data from user page table
7599  *
7600  * return : NO_ERROR
7601  * thread_p (in) : thread entry
7602  * extdata (in) : extensible data
7603  * stop (in) : not used
7604  * args (in) : FILE *
7605  */
7606 static int
7607 file_user_page_table_extdata_dump (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop,
7608  void *args)
7609 {
7610  FILE *fp = (FILE *) args;
7611 
7612  fprintf (fp, FILE_EXTDATA_MSG ("user page table component"), FILE_EXTDATA_AS_ARGS (extdata));
7613  return NO_ERROR;
7614 }
7615 
7616 /*
7617  * file_user_page_table_item_dump () - dump an item from user page table
7618  *
7619  * return : NO_ERROR
7620  * thread_p (in) : thread entry
7621  * data (in) : VPID *
7622  * index (in) : item index
7623  * stop (in) : not used
7624  * args (in) : FILE *
7625  */
7626 static int
7627 file_user_page_table_item_dump (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args)
7628 {
7629  FILE *fp = (FILE *) args;
7630  VPID *vpid = (VPID *) data;
7631 
7632  if (index % 8 == 0)
7633  {
7634  fprintf (fp, "\n\t\t\t");
7635  }
7637  {
7638  fprintf (fp, "\n WARNING: page %d|%d is marked as deleted!! \n\t\t\t", VPID_AS_ARGS (vpid));
7639  }
7640  fprintf (fp, "%5d|%10d ", VPID_AS_ARGS (vpid));
7641 
7642  return NO_ERROR;
7643 }
7644 
7645 /*
7646  * file_spacedb () - get space usage information
7647  *
7648  * return : error code
7649  * thread_p (in) : thread entry
7650  * spacedb (out) : output space usage information
7651  */
7652 int
7654 {
7655  int i;
7656  int error_code = NO_ERROR;
7657 
7658  /* init */
7659  memset (spacedb, 0, sizeof (SPACEDB_FILES) * SPACEDB_FILE_COUNT);
7660 
7661  /* temporary files stats are already cached. */
7662  spacedb[SPACEDB_TEMP_FILE] = file_Tempcache->spacedb_temp;
7663 
7664  /* use file tracker to get info on permanent purpose files */
7665  error_code = file_tracker_spacedb (thread_p, spacedb);
7666  if (error_code != NO_ERROR)
7667  {
7668  ASSERT_ERROR ();
7669  return error_code;
7670  }
7671 
7672  /* compute total */
7673  memset (&spacedb[SPACEDB_TOTAL_FILE], 0, sizeof (spacedb[SPACEDB_TOTAL_FILE]));
7674  for (i = 0; i < SPACEDB_TOTAL_FILE; i++)
7675  {
7676  spacedb[SPACEDB_TOTAL_FILE].nfile += spacedb[i].nfile;
7677  spacedb[SPACEDB_TOTAL_FILE].npage_ftab += spacedb[i].npage_ftab;
7678  spacedb[SPACEDB_TOTAL_FILE].npage_user += spacedb[i].npage_user;
7679  spacedb[SPACEDB_TOTAL_FILE].npage_reserved += spacedb[i].npage_reserved;
7680  }
7681  return NO_ERROR;
7682 }
7683 
7684 /************************************************************************/
7685 /* Numerable files section. */
7686 /************************************************************************/
7687 
7688 /*
7689  * file_numerable_add_page () - Add a page at the end of user page table. This is part of the implementation for
7690  * numerable files.
7691  *
7692  * return : Error code
7693  * thread_p (in) : Thread entry
7694  * page_fhead (in) : File header page
7695  * vpid (in) : VPID of page to add to use page table.
7696  */
7697 static int
7698 file_numerable_add_page (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, const VPID * vpid)
7699 {
7700  FILE_HEADER *fhead = (FILE_HEADER *) page_fhead;
7701  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab = NULL;
7702  VPID vpid_fhead;
7703  PAGE_PTR page_ftab = NULL;
7704  PAGE_PTR page_extdata = NULL;
7705  LOG_LSA save_lsa;
7706  int error_code = NO_ERROR;
7707 
7708  assert (fhead != NULL);
7709  assert (vpid != NULL && !VPID_ISNULL (vpid));
7710  assert (FILE_IS_NUMERABLE (fhead));
7711 
7712  /* how it works:
7713  * we need to add the page at the end of user page table. the order of pages in numerable files is the same as their
7714  * allocation order, so we always add a page at the end.
7715  *
7716  * note: fhead->vpid_last_user_page_ftab is a hint to last page in user page table, where the VPID should be added.
7717  */
7718 
7719  FILE_GET_HEADER_VPID (&fhead->self, &vpid_fhead);
7720 
7721  /* we have a hint on where the page must be added */
7722  if (VPID_EQ (&fhead->vpid_last_user_page_ftab, &vpid_fhead))
7723  {
7724  /* hint points to file header */
7725  page_extdata = page_fhead;
7726  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
7727  }
7728  else
7729  {
7730  /* hint points to another table page. */
7731  page_ftab =
7733  if (page_ftab == NULL)
7734  {
7735  ASSERT_ERROR_AND_SET (error_code);
7736  goto exit;
7737  }
7738  page_extdata = page_ftab;
7739  extdata_user_page_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
7740  }
7741 
7742  file_log ("file_numerable_add_page",
7743  "file %d|%d add page %d|%d to user page table \n"
7745  FILE_EXTDATA_MSG ("last user page table component"),
7746  VFID_AS_ARGS (&fhead->self), VPID_AS_ARGS (vpid),
7747  FILE_HEAD_FULL_AS_ARGS (fhead), FILE_EXTDATA_AS_ARGS (extdata_user_page_ftab));
7748 
7749  if (file_extdata_is_full (extdata_user_page_ftab))
7750  {
7751  /* no more room for new pages. allocate a new table page. */
7752  VPID vpid_ftab_new = VPID_INITIALIZER;
7753 
7754  if (FILE_IS_TEMPORARY (fhead))
7755  {
7756  /* we can have temporary numerable files */
7757  error_code = file_temp_alloc (thread_p, page_fhead, FILE_ALLOC_TABLE_PAGE, &vpid_ftab_new);
7758  if (error_code != NO_ERROR)
7759  {
7760  ASSERT_ERROR ();
7761  goto exit;
7762  }
7763  }
7764  else
7765  {
7766  error_code = file_perm_alloc (thread_p, page_fhead, FILE_ALLOC_TABLE_PAGE, &vpid_ftab_new);
7767  if (error_code != NO_ERROR)
7768  {
7769  ASSERT_ERROR ();
7770  goto exit;
7771  }
7772  }
7773  assert (!VPID_ISNULL (&vpid_ftab_new));
7774 
7775  /* create a link from previous page table. */
7776  if (!FILE_IS_TEMPORARY (fhead))
7777  {
7778  /* log setting next page */
7779  file_log_extdata_set_next (thread_p, extdata_user_page_ftab, page_extdata, &vpid_ftab_new);
7780  }
7781  else
7782  {
7783  /* just set dirty */
7784  pgbuf_set_dirty (thread_p, page_extdata, DONT_FREE);
7785  }
7786  VPID_COPY (&extdata_user_page_ftab->vpid_next, &vpid_ftab_new);
7787  if (page_ftab != NULL)
7788  {
7789  /* we don't need it anymore */
7790  pgbuf_set_dirty_and_free (thread_p, page_ftab);
7791  }
7792 
7793  /* fix new table page */
7794  page_ftab = pgbuf_fix (thread_p, &vpid_ftab_new, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
7795  if (page_ftab == NULL)
7796  {
7797  ASSERT_ERROR_AND_SET (error_code);
7798  goto exit;
7799  }
7800  page_extdata = page_ftab;
7801  pgbuf_set_page_ptype (thread_p, page_ftab, PAGE_FTAB);
7802 
7803  save_lsa = *pgbuf_get_lsa (page_fhead);
7804  if (!FILE_IS_TEMPORARY (fhead))
7805  {
7806  /* log that we are going to change fhead->vpid_last_page_ftab. */
7807  log_append_undoredo_data2 (thread_p, RVFL_FHEAD_SET_LAST_USER_PAGE_FTAB, NULL, page_fhead, 0, sizeof (VPID),
7808  sizeof (VPID), &fhead->vpid_last_user_page_ftab, &vpid_ftab_new);
7809  }
7810 
7811  VPID_COPY (&fhead->vpid_last_user_page_ftab, &vpid_ftab_new);
7812  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
7813 
7814  file_log ("file_numerable_add_page",
7815  "file %d|%d added new page %d|%d to user table; "
7816  "updated vpid_last_user_page_ftab in header page %d|%d, prev_lsa %lld|%d, crt_lsa %lld|%d ",
7817  VFID_AS_ARGS (&fhead->self), VPID_AS_ARGS (&vpid_ftab_new),
7818  PGBUF_PAGE_MODIFY_ARGS (page_fhead, &save_lsa));
7819 
7820  /* initialize new page table */
7821  extdata_user_page_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
7822  file_extdata_init (sizeof (VPID), DB_PAGESIZE, extdata_user_page_ftab);
7823 
7824  if (!FILE_IS_TEMPORARY (fhead))
7825  {
7826  /* log changes. */
7827  pgbuf_log_new_page (thread_p, page_ftab, file_extdata_size (extdata_user_page_ftab), PAGE_FTAB);
7828  }
7829  else
7830  {
7831  /* just set dirty */
7832  pgbuf_set_dirty (thread_p, page_ftab, DONT_FREE);
7833  }
7834  }
7835 
7836  assert (!file_extdata_is_full (extdata_user_page_ftab));
7837  save_lsa = *pgbuf_get_lsa (page_extdata);
7838  if (!FILE_IS_TEMPORARY (fhead))
7839  {
7840  /* log changes */
7841  file_log_extdata_add (thread_p, extdata_user_page_ftab, page_extdata,
7842  file_extdata_item_count (extdata_user_page_ftab), 1, vpid);
7843  }
7844  else
7845  {
7846  /* just set dirty */
7847  pgbuf_set_dirty (thread_p, page_extdata, DONT_FREE);
7848  }
7849  file_extdata_append (extdata_user_page_ftab, vpid);
7850 
7851  file_log ("file_numerable_add_page",
7852  "add page %d|%d to position %d in file %d|%d, page %d|%d, prev_lsa = %lld|%d, crt_lsa = %lld|%d \n"
7853  FILE_EXTDATA_MSG ("last user page table component") FILE_HEAD_FULL_MSG, VPID_AS_ARGS (vpid),
7854  file_extdata_item_count (extdata_user_page_ftab) - 1, VFID_AS_ARGS (&fhead->self),
7855  PGBUF_PAGE_MODIFY_ARGS (page_extdata, &save_lsa), FILE_EXTDATA_AS_ARGS (extdata_user_page_ftab),
7856  FILE_HEAD_FULL_AS_ARGS (fhead));
7857 
7858  /* done */
7859  assert (error_code == NO_ERROR);
7860 
7861 exit:
7862  if (page_ftab != NULL)
7863  {
7864  assert (page_ftab != page_fhead);
7865  pgbuf_unfix (thread_p, page_ftab);
7866  }
7867 
7868  return error_code;
7869 }
7870 
7871 /*
7872  * file_extdata_find_nth_vpid () - Function callable by file_extdata_apply_funcs. An optimal way of finding nth page
7873  * when there is no page marked as deleted.
7874  *
7875  * return : NO_ERROR
7876  * thread_p (in) : Thread entry
7877  * extdata (in) : Extensible data
7878  * stop (in) : Output true when search must be stopped
7879  * args (in) : FILE_FIND_NTH_CONTEXT *
7880  */
7881 static int
7882 file_extdata_find_nth_vpid (THREAD_ENTRY * thread_p, const FILE_EXTENSIBLE_DATA * extdata, bool * stop, void *args)
7883 {
7884  FILE_FIND_NTH_CONTEXT *find_nth_context = (FILE_FIND_NTH_CONTEXT *) args;
7885  int count_vpid = file_extdata_item_count (extdata);
7886 
7887  if (count_vpid <= find_nth_context->nth)
7888  {
7889  /* not in this extensible data. continue searching. */
7890  find_nth_context->nth -= count_vpid;
7891  find_nth_context->first_index += count_vpid;
7892  }
7893  else
7894  {
7895  /* nth VPID is in this extensible data. get it and stop searching */
7896  VPID_COPY (find_nth_context->vpid_nth, (VPID *) file_extdata_at (extdata, find_nth_context->nth));
7897  assert (!FILE_USER_PAGE_IS_MARKED_DELETED (find_nth_context->vpid_nth));
7898  *stop = true;
7899  }
7900 
7901  return NO_ERROR;
7902 }
7903 
7904 /*
7905  * file_extdata_find_nth_vpid_and_skip_marked () - Function callable by file_extdata_apply_funcs. Used to find the nth
7906  * VPID not marked as deleted (numerable files).
7907  *
7908  * return : NO_ERROR
7909  * thread_p (in) : Thread entry
7910  * data (in) : Pointer in user page table (VPID *).
7911  * index (in) : Not used.
7912  * stop (out) : Output true when nth page is reached.
7913  * args (in/out) : FILE_FIND_NTH_CONTEXT *
7914  */
7915 static int
7917  const void *data, int index, bool * stop, void *args)
7918 {
7919  FILE_FIND_NTH_CONTEXT *find_nth_context = (FILE_FIND_NTH_CONTEXT *) args;
7920  VPID *vpidp = (VPID *) data;
7921 
7923  {
7924  /* skip marked deleted */
7925  return NO_ERROR;
7926  }
7927 
7928  if (find_nth_context->nth == 0)
7929  {
7930  /* found nth */
7931  *find_nth_context->vpid_nth = *vpidp;
7932  *stop = true;
7933  }
7934  else
7935  {
7936  /* update nth */
7937  find_nth_context->nth--;
7938  }
7939 
7940  return NO_ERROR;
7941 }
7942 
7943 /*
7944  * file_numerable_find_nth () - Find nth page VPID in numerable file.
7945  *
7946  * return : Error code
7947  * thread_p (in) : Thread entry
7948  * vfid (in) : File identifier
7949  * nth (in) : Index of page
7950  * auto_alloc (in) : True to allow file extension.
7951  * f_init (in) : init page function (must not be NULL for permanent page allocation)
7952  * f_init_args (in) : arguments for init page function
7953  * vpid_nth (out) : VPID at index
7954  */
7955 int
7956 file_numerable_find_nth (THREAD_ENTRY * thread_p, const VFID * vfid, int nth, bool auto_alloc,
7957  FILE_INIT_PAGE_FUNC f_init, void *f_init_args, VPID * vpid_nth)
7958 {
7959  VPID vpid_fhead;
7960  PAGE_PTR page_fhead = NULL;
7961  FILE_HEADER *fhead = NULL;
7962  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab = NULL;
7963  PAGE_PTR page_ftab_start = NULL;
7964  PAGE_PTR page_ftab_nth_location = NULL;
7965  FILE_FIND_NTH_CONTEXT find_nth_context;
7966  int error_code = NO_ERROR;
7967 
7968  assert (vfid != NULL && !VFID_ISNULL (vfid));
7969  assert (nth >= 0);
7970  assert (vpid_nth != NULL);
7971 
7972  VPID_SET_NULL (vpid_nth);
7973 
7974  /* how it works:
7975  * iterate through user page table, skipping pages marked as deleted, and decrement counter until it reaches 0.
7976  * save the VPID found on the nth position.
7977  * if there are no marked deleted pages, we can skip entire extensible data components and go directly to nth page.
7978  */
7979 
7980  /* get file header */
7981  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
7982  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
7983  if (page_fhead == NULL)
7984  {
7985  ASSERT_ERROR_AND_SET (error_code);
7986  goto exit;
7987  }
7988  fhead = (FILE_HEADER *) page_fhead;
7989  file_header_sanity_check (thread_p, fhead);
7990  assert (FILE_IS_NUMERABLE (fhead));
7991  assert (nth < fhead->n_page_user || (auto_alloc && nth == fhead->n_page_user));
7992 
7993  if (auto_alloc && nth == (fhead->n_page_user - fhead->n_page_mark_delete))
7994  {
7995  /* we need new page */
7996  /* todo: can this be simplified? */
7997  error_code = pgbuf_promote_read_latch (thread_p, &page_fhead, PGBUF_PROMOTE_SHARED_READER);
7998  if (error_code == ER_PAGE_LATCH_PROMOTE_FAIL)
7999  {
8000  /* re-fix page */
8001  pgbuf_unfix (thread_p, page_fhead);
8002  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
8003  if (page_fhead == NULL)
8004  {
8005  ASSERT_ERROR_AND_SET (error_code);
8006  goto exit;
8007  }
8008  fhead = (FILE_HEADER *) page_fhead;
8009  file_header_sanity_check (thread_p, fhead);
8010  if (auto_alloc && nth == (fhead->n_page_user - fhead->n_page_mark_delete))
8011  {
8012  error_code = file_alloc (thread_p, vfid, f_init, f_init_args, vpid_nth, NULL);
8013  if (error_code != NO_ERROR)
8014  {
8015  ASSERT_ERROR ();
8016  }
8017  goto exit;
8018  }
8019  }
8020  else if (error_code != NO_ERROR)
8021  {
8022  ASSERT_ERROR ();
8023  goto exit;
8024  }
8025  else if (page_fhead == NULL)
8026  {
8027  ASSERT_ERROR_AND_SET (error_code);
8028  goto exit;
8029  }
8030 
8031  error_code = file_alloc (thread_p, vfid, f_init, f_init_args, vpid_nth, NULL);
8032  if (error_code != NO_ERROR)
8033  {
8034  ASSERT_ERROR ();
8035  }
8036 
8037  goto exit;
8038  }
8039 
8040  /* iterate in user page table */
8041  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
8042  find_nth_context.vpid_nth = vpid_nth;
8043  find_nth_context.nth = nth;
8044 
8045  if (fhead->n_page_mark_delete > 0)
8046  {
8047  /* we don't know where the marked deleted pages are... we need to iterate through all pages and skip the marked
8048  * deleted. */
8049  error_code = file_extdata_apply_funcs (thread_p, extdata_user_page_ftab, NULL, NULL,
8050  file_extdata_find_nth_vpid_and_skip_marked, &find_nth_context, false,
8051  NULL, NULL);
8052  if (error_code != NO_ERROR)
8053  {
8054  ASSERT_ERROR ();
8055  goto exit;
8056  }
8057  }
8058  else
8059  {
8060  if (FILE_CACHE_LAST_FIND_NTH (fhead) && !VPID_ISNULL (&fhead->vpid_find_nth_last)
8061  && !VPID_EQ (&vpid_fhead, &fhead->vpid_find_nth_last) && nth >= fhead->first_index_find_nth_last)
8062  {
8063  /* start searching from last search location */
8064  page_ftab_start =
8066  if (page_ftab_start == NULL)
8067  {
8068  ASSERT_ERROR_AND_SET (error_code);
8069  goto exit;
8070  }
8071  extdata_user_page_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab_start;
8072  find_nth_context.first_index = fhead->first_index_find_nth_last;
8073  find_nth_context.nth -= fhead->first_index_find_nth_last;
8074  }
8075  else
8076  {
8077  /* no last search location or it could not be used. start searching from the beginning. */
8078  find_nth_context.first_index = 0;
8079  }
8080  /* we can go directly to the right VPID. */
8081  error_code = file_extdata_apply_funcs (thread_p, extdata_user_page_ftab, file_extdata_find_nth_vpid,
8082  &find_nth_context, NULL, NULL, false, NULL, &page_ftab_nth_location);
8083  if (error_code != NO_ERROR)
8084  {
8085  ASSERT_ERROR ();
8086  goto exit;
8087  }
8088 
8089  if (FILE_CACHE_LAST_FIND_NTH (fhead))
8090  {
8091  /* note that we consider this file cannot be accessed concurrently. therefore we do not promote to write latch
8092  * and we do not set page dirty to update the cached search location. */
8093  if (page_ftab_nth_location == NULL)
8094  {
8095  /* it was found in the starting page */
8096  page_ftab_nth_location = page_ftab_start != NULL ? page_ftab_start : page_fhead;
8097  }
8098  pgbuf_get_vpid (page_ftab_nth_location, &fhead->vpid_find_nth_last);
8099  fhead->first_index_find_nth_last = find_nth_context.first_index;
8100 
8101  file_log ("file_numerable_find_nth", "update fhead.fist_index_find_nth_last to %d "
8102  "and fhead->vpid_find_nth_last to %d|%d while searching nth=%d in file %d|%d",
8104  VFID_AS_ARGS (vfid));
8105  }
8106  }
8107 
8108  if (VPID_ISNULL (vpid_nth))
8109  {
8110  /* should not happen */
8111  assert_release (false);
8112  error_code = ER_FAILED;
8113  goto exit;
8114  }
8115 
8116  assert (error_code == NO_ERROR);
8117 
8118 exit:
8119  if (page_ftab_nth_location != NULL && page_ftab_nth_location != page_ftab_start
8120  && page_ftab_nth_location != page_fhead)
8121  {
8122  pgbuf_unfix (thread_p, page_ftab_nth_location);
8123  }
8124  if (page_ftab_start != NULL)
8125  {
8126  pgbuf_unfix (thread_p, page_ftab_start);
8127  }
8128  if (page_fhead != NULL)
8129  {
8130  pgbuf_unfix (thread_p, page_fhead);
8131  }
8132 
8133  return error_code;
8134 }
8135 
8136 /*
8137  * file_rv_user_page_mark_delete () - Recover page mark delete.
8138  *
8139  * return : Error code
8140  * thread_p (in) : Thread entry
8141  * rcv (in) : Recovery data
8142  */
8143 int
8145 {
8146  PAGE_PTR page_ftab = rcv->pgptr;
8147  VPID *vpid_ptr = NULL;
8148 
8149  vpid_ptr = (VPID *) (page_ftab + rcv->offset);
8151  FILE_USER_PAGE_MARK_DELETED (vpid_ptr);
8152 
8153  file_log ("file_rv_user_page_mark_delete",
8154  "marked deleted vpid %d|%d in page %d|%d lsa %lld|%d at offset %d",
8155  VPID_AS_ARGS (vpid_ptr), PGBUF_PAGE_STATE_ARGS (page_ftab), rcv->offset);
8156 
8157  pgbuf_set_dirty (thread_p, page_ftab, DONT_FREE);
8158  return NO_ERROR;
8159 }
8160 
8161 /*
8162  * file_rv_user_page_unmark_delete_logical () - Recover page unmark delete (logical)
8163  *
8164  * return : Error code
8165  * thread_p (in) : Thread entry
8166  * rcv (in) : Recovery data
8167  */
8168 int
8170 {
8171  PAGE_PTR page_fhead;
8172  PAGE_PTR page_ftab;
8173  FILE_HEADER *fhead;
8174  VFID *vfid;
8175  VPID *vpid;
8176  VPID *vpid_in_table;
8177  VPID vpid_fhead;
8178  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab;
8180  bool found = false;
8181  int position = -1;
8182  int offset = 0;
8183  LOG_LSA save_lsa;
8184  int error_code = NO_ERROR;
8185 
8186  /* how it works
8187  * when we mark a page as deleted in user page table and unfix file header, the user page table can be modified by
8188  * concurrent transactions. if allocations are always appended at the end, deallocations will remove VPID's from
8189  * user page table and can sometime merge pages. which means that by the time we get to undo our change, the location
8190  * of this page becomes uncertain.
8191  *
8192  * therefore, removing mark for deletion should lookup VPID in table.
8193  */
8194 
8195  vfid = (VFID *) (rcv->data + offset);
8196  offset += sizeof (*vfid);
8197 
8198  vpid = (VPID *) (rcv->data + offset);
8199  offset += sizeof (*vpid);
8200 
8201  assert (offset == rcv->length);
8202 
8203  vpid_fhead.volid = vfid->volid;
8204  vpid_fhead.pageid = vfid->fileid;
8205  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
8206  if (page_fhead == NULL)
8207  {
8208  /* Should not be interrupted. */
8209  assert_release (false);
8210  return ER_FAILED;
8211  }
8212 
8213  fhead = (FILE_HEADER *) page_fhead;
8214 
8215  assert (FILE_IS_NUMERABLE (fhead));
8216  assert (!FILE_IS_TEMPORARY (fhead));
8217 
8218  /* search for VPID in user page table */
8219  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
8220  error_code =
8221  file_extdata_search_item (thread_p, &extdata_user_page_ftab, vpid,
8222  file_compare_vpids, false, true, &found, &position, &page_ftab);
8223  if (error_code != NO_ERROR)
8224  {
8225  /* errors not expected during recovery. */
8226  assert_release (false);
8227  goto exit;
8228  }
8229  if (!found)
8230  {
8231  /* should be found. */
8232  assert_release (false);
8233  error_code = ER_FAILED;
8234  goto exit;
8235  }
8236 
8237  /* go to VPID in current extensible data */
8238  vpid_in_table = (VPID *) file_extdata_at (extdata_user_page_ftab, position);
8239  assert (FILE_USER_PAGE_IS_MARKED_DELETED (vpid_in_table));
8240 
8241  FILE_USER_PAGE_CLEAR_MARK_DELETED (vpid_in_table);
8242  assert (VPID_EQ (vpid, vpid_in_table));
8243 
8244  /* compensate logging. */
8245  addr.pgptr = page_ftab != NULL ? page_ftab : page_fhead;
8246  addr.offset = (PGLENGTH) (((char *) vpid_in_table) - addr.pgptr);
8247  save_lsa = *pgbuf_get_lsa (addr.pgptr);
8249  addr.pgptr, 0, NULL, LOG_FIND_CURRENT_TDES (thread_p));
8250 
8251  file_log ("file_rv_user_page_unmark_delete_logical",
8252  "unmark delete vpid %d|%d in file %d|%d, page %d|%d, "
8253  "prev_lsa %lld|%d, crt_lsa %lld|%d, at offset %d",
8254  VPID_AS_ARGS (vpid_in_table), VFID_AS_ARGS (vfid), PGBUF_PAGE_MODIFY_ARGS (addr.pgptr, &save_lsa),
8255  addr.offset);
8256 
8257  pgbuf_set_dirty (thread_p, addr.pgptr, DONT_FREE);
8258 
8259  /* done */
8260  assert (error_code == NO_ERROR);
8261 
8262 exit:
8263  if (page_ftab != NULL)
8264  {
8265  pgbuf_unfix (thread_p, page_ftab);
8266  }
8267  if (page_fhead != NULL)
8268  {
8269  pgbuf_unfix (thread_p, page_fhead);
8270  }
8271  return error_code;
8272 }
8273 
8274 /*
8275  * file_rv_user_page_unmark_delete_physical () - Recover page unmark delete (physical)
8276  *
8277  * return : Error code
8278  * thread_p (in) : Thread entry
8279  * rcv (in) : Recovery data
8280  */
8281 int
8283 {
8284  PAGE_PTR page_ftab = rcv->pgptr;
8285  VPID *vpid_ptr = NULL;
8286 
8287  /* note: this is used to compensate undo of mark delete. this time the location of VPID is known */
8288 
8289  vpid_ptr = (VPID *) (page_ftab + rcv->offset);
8291 
8293 
8294  file_log ("file_rv_user_page_unmark_delete_physical",
8295  "unmark delete vpid %d|%d in page %d|%d, lsa %lld|%d, "
8296  "at offset %d", VPID_AS_ARGS (vpid_ptr), PGBUF_PAGE_STATE_ARGS (page_ftab), rcv->offset);
8297 
8298  pgbuf_set_dirty (thread_p, page_ftab, DONT_FREE);
8299  return NO_ERROR;
8300 }
8301 
8302 /*
8303  * file_table_check_page_is_in_sectors () - FILE_EXTDATA_ITEM_FUNC to check user page table is in one of the sectors
8304  *
8305  * return : error code
8306  * thread_p (in) : thread entry
8307  * data (in) : user page table entry
8308  * index (in) : index of user page table entry
8309  * stop (in) : not used
8310  * args (in) : FILE_VSID_COLLECTOR *
8311  */
8312 static int
8313 file_table_check_page_is_in_sectors (THREAD_ENTRY * thread_p, const void *data, int index, bool * stop, void *args)
8314 {
8315  FILE_VSID_COLLECTOR *collector = (FILE_VSID_COLLECTOR *) args;
8316  VPID vpid = *(VPID *) data;
8317  VSID vsid_of_vpid;
8318 
8320  VSID_FROM_VPID (&vsid_of_vpid, &vpid);
8321 
8322  if (bsearch (&vsid_of_vpid, collector->vsids, collector->n_vsids, sizeof (VSID), disk_compare_vsids) == NULL)
8323  {
8324  /* not found! */
8325  assert_release (false);
8326  return ER_FAILED;
8327  }
8328  return NO_ERROR;
8329 }
8330 
8331 /*
8332  * file_numerable_truncate () - truncate numerable files to a smaller number of pages
8333  *
8334  * return : error code
8335  * thread_p (in) : thread entry
8336  * vfid (in) : file identifier
8337  * npages (in) : desired number of pages
8338  */
8339 int
8340 file_numerable_truncate (THREAD_ENTRY * thread_p, const VFID * vfid, DKNPAGES npages)
8341 {
8342  VPID vpid_fhead;
8343  PAGE_PTR page_fhead = NULL;
8344  FILE_HEADER *fhead;
8345  VPID vpid;
8346  int error_code = NO_ERROR;
8347 
8348  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
8349  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
8350  if (page_fhead == NULL)
8351  {
8352  ASSERT_ERROR_AND_SET (error_code);
8353  return ER_FAILED;
8354  }
8355  fhead = (FILE_HEADER *) page_fhead;
8356 
8357  if (!FILE_IS_NUMERABLE (fhead))
8358  {
8359  /* cannot truncate */
8360  assert_release (false);
8361  error_code = ER_FAILED;
8362  goto exit;
8363  }
8364 
8365  if (fhead->n_page_mark_delete != 0)
8366  {
8367  /* I am not sure what we should do in this case. We give up truncating and in debug it will crash. */
8368  assert (false);
8369  return NO_ERROR;
8370  }
8371 
8372  while (fhead->n_page_user > npages)
8373  {
8374  /* maybe this can be done in a more optimal way... but for now it will have to do */
8375  error_code = file_numerable_find_nth (thread_p, vfid, npages, false, NULL, NULL, &vpid);
8376  if (error_code != NO_ERROR)
8377  {
8378  ASSERT_ERROR ();
8379  goto exit;
8380  }
8381  error_code = file_dealloc (thread_p, vfid, &vpid, fhead->type);
8382  if (error_code != NO_ERROR)
8383  {
8384  ASSERT_ERROR ();
8385  goto exit;
8386  }
8387  }
8388  assert (fhead->n_page_user == npages);
8389  assert (error_code == NO_ERROR);
8390 
8391 exit:
8392  if (page_fhead != NULL)
8393  {
8394  pgbuf_unfix (thread_p, page_fhead);
8395  }
8396  return error_code;
8397 }
8398 
8399 /************************************************************************/
8400 /* Temporary files section. */
8401 /************************************************************************/
8402 
8403 /*
8404  * file_temp_alloc () - Allocate a new page in temporary file.
8405  *
8406  * return : Error code
8407  * thread_p (in) : Thread entry
8408  * page_fhead (in) : File header page
8409  * alloc_type (in) : User/table page
8410  * vpid_alloc_out (out) : Output allocated page VPID.
8411  */
8412 static int
8413 file_temp_alloc (THREAD_ENTRY * thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, VPID * vpid_alloc_out)
8414 {
8415  FILE_HEADER *fhead = (FILE_HEADER *) page_fhead;
8416  VPID vpid_fhead;
8417  FILE_EXTENSIBLE_DATA *extdata_part_ftab = NULL;
8418  PAGE_PTR page_ftab = NULL;
8419  FILE_PARTIAL_SECTOR *partsect = NULL;
8420  bool was_empty = false;
8421  bool is_full = false;
8422  /* we don't have rollback, so don't interrupt */
8423  bool save_check_interrupt = logtb_set_check_interrupt (thread_p, false);
8424  int error_code = NO_ERROR;
8425 
8426  file_header_sanity_check (thread_p, fhead);
8427  assert (FILE_IS_TEMPORARY (fhead));
8428  assert (page_fhead != NULL);
8429  assert (vpid_alloc_out != NULL);
8430 
8431  /* how it works
8432  * temporary files, compared to permanent files, have a simplified design. they do not keep two different tables
8433  * (partial and full). they only keep the partial table, and when sectors become full, they remain in the partial
8434  * table.
8435  * the second difference is that temporary files never deallocate pages. since they are temporary, and soon to be
8436  * freed (or cached for reuse), there is no point in deallocating pages.
8437  * the simplified design was chosen because temporary files are never logged. and it is hard to undo changes without
8438  * logging when errors happen (e.g. interrupted transaction).
8439  *
8440  * all we have to do to allocate a page is to try to allocate from last used sector. if that sector is full, advance
8441  * to next sector. if no new sectors, reserve a new one. that's all.
8442  */
8443 
8444  file_log ("file_temp_alloc", "%s", FILE_ALLOC_TYPE_STRING (alloc_type));
8445 
8446  FILE_GET_HEADER_VPID (&fhead->self, &vpid_fhead);
8447 
8448  /* get page for last allocated partial table */
8449  if (VPID_EQ (&vpid_fhead, &fhead->vpid_last_temp_alloc))
8450  {
8451  /* partial table in header */
8452  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
8453  }
8454  else
8455  {
8456  page_ftab =
8458  if (page_ftab == NULL)
8459  {
8460  assert_release (false);
8461  error_code = ER_FAILED;
8462  goto exit;
8463  }
8464  extdata_part_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
8465  }
8466 
8467  if (fhead->n_page_free == 0)
8468  {
8469  /* expand file by one sector */
8471 
8472  /* reserve a sector */
8473  error_code =
8474  disk_reserve_sectors (thread_p, DB_TEMPORARY_DATA_PURPOSE, fhead->volid_last_expand, 1, &partsect_new.vsid);
8475  if (error_code != NO_ERROR)
8476  {
8477  assert_release (false);
8478  goto exit;
8479  }
8480 
8481  file_log ("file_temp_alloc",
8482  "no free pages" FILE_HEAD_ALLOC_MSG "\texpand file with VSID = %d|%d ",
8483  FILE_HEAD_ALLOC_AS_ARGS (fhead), VSID_AS_ARGS (&partsect_new.vsid));
8484 
8485  assert (extdata_part_ftab != NULL);
8486  if (file_extdata_is_full (extdata_part_ftab))
8487  {
8488  /* we need a new page. */
8489  /* we will use first page of newly reserved sector. */
8490  VPID vpid_ftab_new;
8491  PAGE_PTR page_ftab_new = NULL;
8492 
8493  vpid_ftab_new.volid = partsect_new.vsid.volid;
8494  vpid_ftab_new.pageid = SECTOR_FIRST_PAGEID (partsect_new.vsid.sectid);
8495  file_partsect_set_bit (&partsect_new, 0);
8496 
8497  /* fix new file table page */
8498  page_ftab_new = pgbuf_fix (thread_p, &vpid_ftab_new, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
8499  if (page_ftab_new == NULL)
8500  {
8501  error_code = ER_FAILED;
8502 
8503  /* todo: unreserve sector */
8504  goto exit;
8505  }
8506  pgbuf_set_page_ptype (thread_p, page_ftab_new, PAGE_FTAB);
8507 
8508  /* set link to previous page. */
8509  VPID_COPY (&extdata_part_ftab->vpid_next, &vpid_ftab_new);
8510 
8511  /* we don't need old file table page anymore */
8512  assert (page_ftab != page_fhead);
8513  if (page_ftab != NULL)
8514  {
8515  pgbuf_set_dirty_and_free (thread_p, page_ftab);
8516  }
8517 
8518  VPID_COPY (&fhead->vpid_last_temp_alloc, &vpid_ftab_new);
8519  fhead->offset_to_last_temp_alloc = 0;
8520  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
8521 
8522  page_ftab = page_ftab_new;
8523  extdata_part_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
8524  file_extdata_init (sizeof (FILE_PARTIAL_SECTOR), DB_PAGESIZE, extdata_part_ftab);
8525 
8526  file_log ("file_temp_alloc",
8527  "used newly reserved sector's first page %d|%d for partial table.", VPID_AS_ARGS (&vpid_ftab_new));
8528 
8529  /* update temporary file stats - DISK_SECTOR_NPAGES -1 reserved pages and 1 file table page. */
8530  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_reserved, DISK_SECTOR_NPAGES - 1);
8531  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_ftab, 1);
8532  }
8533  else
8534  {
8535  /* update temporary file stats - DISK_SECTOR_NPAGES reserved pages */
8536  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_reserved, DISK_SECTOR_NPAGES);
8537  }
8538  assert (!file_extdata_is_full (extdata_part_ftab));
8539  assert (file_extdata_item_count (extdata_part_ftab) == fhead->offset_to_last_temp_alloc);
8540  file_extdata_append (extdata_part_ftab, &partsect_new);
8541 
8542  fhead->n_sector_partial++;
8543  fhead->n_sector_total++;
8544  fhead->n_page_free += DISK_SECTOR_NPAGES;
8545  fhead->n_page_total += DISK_SECTOR_NPAGES;
8546  if (partsect_new.page_bitmap == FILE_EMPTY_PAGE_BITMAP)
8547  {
8548  fhead->n_sector_empty++;
8549  }
8550  else
8551  {
8552  fhead->n_page_free--;
8553  fhead->n_page_ftab++;
8554  }
8555 
8556  file_log ("file_temp_alloc",
8557  "new partial sector added to partial extensible data:\n"
8558  FILE_PARTSECT_MSG ("newly reserved sector")
8559  FILE_EXTDATA_MSG ("last partial table component"),
8560  FILE_PARTSECT_AS_ARGS (&partsect_new), FILE_EXTDATA_AS_ARGS (extdata_part_ftab));
8561  }
8562  assert (fhead->n_page_free > 0);
8563 
8564  if (fhead->offset_to_last_temp_alloc == file_extdata_item_count (extdata_part_ftab))
8565  {
8566  VPID vpid_next;
8567 
8568  /* must be full */
8569  assert (file_extdata_is_full (extdata_part_ftab));
8570  /* we must have another extensible data */
8571  assert (!VPID_ISNULL (&extdata_part_ftab->vpid_next));
8572 
8573  /* move allocation cursor to next partial table page */
8574  vpid_next = extdata_part_ftab->vpid_next;
8575  if (page_ftab != NULL)
8576  {
8577  pgbuf_unfix_and_init (thread_p, page_ftab);
8578  }
8579  page_ftab = pgbuf_fix (thread_p, &vpid_next, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
8580  if (page_ftab == NULL)
8581  {
8582  assert_release (false);
8583  error_code = ER_FAILED;
8584  goto exit;
8585  }
8586  extdata_part_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
8587 
8588  fhead->vpid_last_temp_alloc = vpid_next;
8589  fhead->offset_to_last_temp_alloc = 0;
8590  }
8591 
8592  assert (extdata_part_ftab != NULL);
8593  assert (fhead->offset_to_last_temp_alloc < file_extdata_item_count (extdata_part_ftab));
8594  partsect = (FILE_PARTIAL_SECTOR *) file_extdata_at (extdata_part_ftab, fhead->offset_to_last_temp_alloc);
8595 
8596  /* Allocate the page. */
8597  was_empty = file_partsect_is_empty (partsect);
8598  if (!file_partsect_alloc (partsect, vpid_alloc_out, NULL))
8599  {
8600  /* full sector? that is unexpected. we must have a logic error. */
8601  assert_release (false);
8602  error_code = ER_FAILED;
8603  goto exit;
8604  }
8605  if (file_partsect_is_full (partsect))
8606  {
8607  is_full = true;
8608  fhead->offset_to_last_temp_alloc++;
8609  }
8610 
8611  file_header_alloc (fhead, alloc_type, was_empty, is_full);
8612  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
8613 
8614  file_log ("file_temp_alloc", "%s %d|%d successful. \n" FILE_HEAD_FULL_MSG
8615  FILE_PARTSECT_MSG ("partial sector after alloc"),
8616  FILE_ALLOC_TYPE_STRING (alloc_type),
8617  VPID_AS_ARGS (vpid_alloc_out), FILE_HEAD_FULL_AS_ARGS (fhead), FILE_PARTSECT_AS_ARGS (partsect));
8618 
8619  if (page_ftab != NULL)
8620  {
8621  assert (page_ftab != page_fhead);
8622  pgbuf_set_dirty_and_free (thread_p, page_ftab);
8623  }
8624 
8625  /* update temporary file stats */
8626  if (alloc_type == FILE_ALLOC_USER_PAGE)
8627  {
8628  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_user, 1);
8629  }
8630  else
8631  {
8632  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_ftab, 1);
8633  }
8634  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_reserved, -1);
8635 
8636  /* done */
8637  assert (error_code == NO_ERROR);
8638 
8639 exit:
8640  file_header_sanity_check (thread_p, fhead);
8641  if (page_ftab != NULL)
8642  {
8643  pgbuf_unfix_and_init (thread_p, page_ftab);
8644  }
8645  (void) logtb_set_check_interrupt (thread_p, save_check_interrupt);
8646  return error_code;
8647 }
8648 
8649 /*
8650  * file_temp_set_type () - set new type in existing temporary file
8651  *
8652  * return : error code
8653  * thread_p (in) : thread entry
8654  * vfid (in) : file identifier
8655  * ftype (in) : new file type
8656  */
8657 STATIC_INLINE int
8658 file_temp_set_type (THREAD_ENTRY * thread_p, VFID * vfid, FILE_TYPE ftype)
8659 {
8660  VPID vpid_fhead;
8661  PAGE_PTR page_fhead = NULL;
8662  FILE_HEADER *fhead = NULL;
8663  int error_code = NO_ERROR;
8664 
8665  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
8666  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
8667  if (page_fhead == NULL)
8668  {
8669  ASSERT_ERROR_AND_SET (error_code);
8670  return error_code;
8671  }
8672  fhead = (FILE_HEADER *) page_fhead;
8673  file_header_sanity_check (thread_p, fhead);
8674 
8675  if (!FILE_IS_TEMPORARY (fhead))
8676  {
8677  /* we cannot change type */
8678  assert_release (false);
8679  error_code = ER_FAILED;
8680  goto exit;
8681  }
8682 
8683  fhead->type = ftype;
8684  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
8685 
8686 exit:
8687  pgbuf_unfix (thread_p, page_fhead);
8688  return error_code;
8689 }
8690 
8691 /*
8692  * file_temp_reset_user_pages () - reset all user pages in temporary file.
8693  *
8694  * return : error code
8695  * thread_p (in) : thread entry
8696  * vfid (in) : file identifier
8697  */
8698 static int
8700 {
8701  VPID vpid_fhead;
8702  PAGE_PTR page_fhead = NULL;
8703  FILE_HEADER *fhead = NULL;
8705  FILE_EXTENSIBLE_DATA *extdata_part_ftab = NULL;
8706  PAGE_PTR page_ftab = NULL;
8707  FILE_PARTIAL_SECTOR *partsect = NULL;
8708  int idx_sect = 0;
8709  VPID vpid_next;
8710  int nsect_part_new;
8711  int nsect_full_new;
8712  int nsect_empty_new;
8713  FILE_EXTENSIBLE_DATA *extdata_user_page_ftab;
8714  bool save_interrupt;
8715  bool found = false;
8716  int error_code = NO_ERROR;
8717 
8718  /* don't let this be interrupted, because we might ruin the file */
8719  save_interrupt = logtb_set_check_interrupt (thread_p, false);
8720 
8721  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
8722  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
8723  if (page_fhead == NULL)
8724  {
8725  ASSERT_ERROR_AND_SET (error_code);
8726  goto exit;
8727  }
8728  fhead = (FILE_HEADER *) page_fhead;
8729  file_header_sanity_check (thread_p, fhead);
8730 
8731  if (!FILE_IS_TEMPORARY (fhead))
8732  {
8733  assert_release (false);
8734  error_code = ER_FAILED;
8735  goto exit;
8736  }
8737 
8738  if (FILE_IS_NUMERABLE (fhead))
8739  {
8740  /* reset user page table */
8741  FILE_HEADER_GET_USER_PAGE_FTAB (fhead, extdata_user_page_ftab);
8742  VPID_SET_NULL (&extdata_user_page_ftab->vpid_next);
8743  extdata_user_page_ftab->n_items = 0;
8744  fhead->vpid_last_user_page_ftab = vpid_fhead;
8745  fhead->vpid_find_nth_last = vpid_fhead;
8746  fhead->first_index_find_nth_last = 0;
8747  }
8748 
8749  /* collect table pages */
8750  error_code = file_table_collect_ftab_pages (thread_p, page_fhead, false, &collector);
8751  if (error_code != NO_ERROR)
8752  {
8753  assert_release (false);
8754  goto exit;
8755  }
8756 
8757  /* count partial, full, empty */
8758  nsect_full_new = 0;
8759  for (idx_sect = 0; idx_sect < collector.nsects; idx_sect++)
8760  {
8761  if (collector.partsect_ftab[idx_sect].page_bitmap == FILE_FULL_PAGE_BITMAP)
8762  {
8763  nsect_full_new++;
8764  }
8765  }
8766  nsect_part_new = collector.nsects - nsect_full_new;
8767  nsect_empty_new = fhead->n_sector_total - collector.nsects;
8768  nsect_part_new += nsect_empty_new;
8769 
8770  /* reset partial table sectors, but leave file table pages allocated */
8771  page_ftab = page_fhead;
8772  FILE_HEADER_GET_PART_FTAB (fhead, extdata_part_ftab);
8773  while (true)
8774  {
8775  assert (extdata_part_ftab != NULL);
8776 
8777  for (partsect = (FILE_PARTIAL_SECTOR *) file_extdata_start (extdata_part_ftab);
8778  partsect < (FILE_PARTIAL_SECTOR *) file_extdata_end (extdata_part_ftab); partsect++)
8779  {
8780  /* does it have file table pages? */
8781  found = false;
8782  for (idx_sect = 0; idx_sect < collector.nsects; idx_sect++)
8783  {
8784  if (disk_compare_vsids (&partsect->vsid, &collector.partsect_ftab[idx_sect].vsid) == 0)
8785  {
8786  /* get bitmap from collector */
8787  partsect->page_bitmap = collector.partsect_ftab[idx_sect].page_bitmap;
8788 
8789  /* sector cannot be found again. remove it from collector */
8790  if (idx_sect < collector.nsects - 1)
8791  {
8792  memmove (&collector.partsect_ftab[idx_sect],
8793  &collector.partsect_ftab[idx_sect + 1],
8794  (collector.nsects - 1 - idx_sect) * sizeof (FILE_PARTIAL_SECTOR));
8795  }
8796  collector.nsects--;
8797  found = true;
8798  break;
8799  }
8800  }
8801  if (!found)
8802  {
8803  /* not found in collector, must be empty sector */
8804  partsect->page_bitmap = FILE_EMPTY_PAGE_BITMAP;
8805  }
8806  }
8807 
8808  pgbuf_set_dirty (thread_p, page_ftab, DONT_FREE);
8809 
8810  vpid_next = extdata_part_ftab->vpid_next;
8811  if (page_ftab != page_fhead)
8812  {
8813  pgbuf_unfix (thread_p, page_ftab);
8814  }
8815  page_ftab = NULL;
8816  if (VPID_ISNULL (&vpid_next))
8817  {
8818  break;
8819  }
8820  page_ftab = pgbuf_fix (thread_p, &vpid_next, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
8821  if (page_ftab == NULL)
8822  {
8823  assert_release (false);
8824  error_code = ER_FAILED;
8825  goto exit;
8826  }
8827  extdata_part_ftab = (FILE_EXTENSIBLE_DATA *) page_ftab;
8828  }
8829  /* partial table sectors have been reset */
8830 
8831  /* update header */
8832  fhead->n_sector_empty = nsect_empty_new;
8833  fhead->n_sector_partial = nsect_part_new;
8834  fhead->n_sector_full = nsect_full_new;
8835 
8836  /* also update temporary files global stats */
8837  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_ftab, collector.npages - fhead->n_page_ftab);
8838  fhead->n_page_ftab = collector.npages;
8839  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_user, -fhead->n_page_user);
8840  fhead->n_page_user = 0;
8841  ATOMIC_INC_32 (&file_Tempcache->spacedb_temp.npage_reserved,
8842  fhead->n_page_total - fhead->n_page_ftab - fhead->n_page_free);
8843  fhead->n_page_free = fhead->n_page_total - fhead->n_page_ftab;
8844 
8845  /* reset pointers used for allocations */
8846  fhead->vpid_last_temp_alloc = vpid_fhead;
8847  fhead->offset_to_last_temp_alloc = 0;
8848 
8849  file_log ("file_temp_reset_user_pages", "finished \n" FILE_HEAD_FULL_MSG, FILE_HEAD_FULL_AS_ARGS (fhead));
8850 
8851  pgbuf_set_dirty (thread_p, page_fhead, DONT_FREE);
8852  /* done */
8853  assert (error_code == NO_ERROR);
8854 
8855 exit:
8856  assert (page_ftab == NULL);
8857 
8858  if (page_fhead != NULL)
8859  {
8860  pgbuf_unfix (thread_p, page_fhead);
8861  }
8862 
8863  (void) logtb_set_check_interrupt (thread_p, save_interrupt);
8864 
8865  if (collector.partsect_ftab != NULL)
8866  {
8867  db_private_free (thread_p, collector.partsect_ftab);
8868  }
8869 
8870  return error_code;
8871 }
8872 
8873 /*
8874  * file_temp_preserve () - preserve temporary file
8875  *
8876  * return :
8877  * THREAD_ENTRY * thread_p (in) :
8878  * const VFID * vfid (in) :
8879  */
8880 void
8881 file_temp_preserve (THREAD_ENTRY * thread_p, const VFID * vfid)
8882 {
8883  /* to preserve the file, we need to remove it from transaction list */
8884  FILE_TEMPCACHE_ENTRY *entry = NULL;
8885 
8886  assert (vfid != NULL && !VFID_ISNULL (vfid));
8887 
8888  entry = file_tempcache_pop_tran_file (thread_p, vfid);
8889  if (entry == NULL)
8890  {
8891  assert_release (false);
8892  }
8893  else
8894  {
8896  }
8897 }
8898 
8899 /************************************************************************/
8900 /* Temporary cache section */
8901 /************************************************************************/
8902 
8903 /*
8904  * file_tempcache_init () - init temporary file cache
8905  *
8906  * return : ER_OUT_OF_VIRTUAL_MEMORY or NO_ERROR
8907  */
8908 static int
8910 {
8911  int memsize = 0;
8912 #if defined (SERVER_MODE)
8913  int ntrans = logtb_get_number_of_total_tran_indices () + 1;
8914 #else
8915  int ntrans = 1;
8916 #endif
8917 
8918  assert (file_Tempcache == NULL);
8919 
8920  /* allocate file_Tempcache */
8921  memsize = sizeof (FILE_TEMPCACHE);
8922  file_Tempcache = (FILE_TEMPCACHE *) malloc (memsize);
8923  if (file_Tempcache == NULL)
8924  {
8926  return ER_OUT_OF_VIRTUAL_MEMORY;
8927  }
8928 
8929  /* initialize free entry list... used to avoid entry allocation/deallocation */
8930  file_Tempcache->free_entries = NULL;
8931  file_Tempcache->nfree_entries_max = ntrans * 8; /* I set 8 per transaction, maybe there is a better value */
8932  file_Tempcache->nfree_entries = 0;
8933 
8934  /* initialize temporary file cache. we keep two separate lists for numerable and regular files */
8935  file_Tempcache->cached_not_numerable = NULL;
8936  file_Tempcache->cached_numerable = NULL;
8938  file_Tempcache->ncached_not_numerable = 0;
8939  file_Tempcache->ncached_numerable = 0;
8940 
8941  /* initialize mutex used to protect temporary file cache and entry allocation/deallocation */
8942  pthread_mutex_init (&file_Tempcache->mutex, NULL);
8943 #if !defined (NDEBUG)
8944  file_Tempcache->owner_mutex = -1;
8945 #endif
8946 
8947  /* allocate transaction temporary files lists */
8948  memsize = ntrans * sizeof (FILE_TEMPCACHE *);
8949  file_Tempcache->tran_files = (FILE_TEMPCACHE_ENTRY **) malloc (memsize);
8950  if (file_Tempcache->tran_files == NULL)
8951  {
8952  pthread_mutex_destroy (&file_Tempcache->mutex);
8953  free_and_init (file_Tempcache);
8955  return ER_OUT_OF_VIRTUAL_MEMORY;
8956  }
8957  memset (file_Tempcache->tran_files, 0, memsize);
8958 
8959  /* stats */
8960  memset (&file_Tempcache->spacedb_temp, 0, sizeof (file_Tempcache->spacedb_temp));
8961 
8962  /* all ok */
8963  return NO_ERROR;
8964 }
8965 
8966 /*
8967  * file_tempcache_final () - free temporary files cache resources
8968  *
8969  * return : void
8970  */
8971 static void
8973 {
8974  int tran = 0;
8975  int ntrans;
8976 
8977  if (file_Tempcache == NULL)
8978  {
8979  return;
8980  }
8981 
8982 #if defined (SERVER_MODE)
8984 #else
8985  ntrans = 1;
8986 #endif
8987 
8989 
8990  /* free all transaction lists... they should be empty anyway, but be conservative */
8991  for (tran = 0; tran < ntrans; tran++)
8992  {
8993  if (file_Tempcache->tran_files[tran] != NULL)
8994  {
8995  /* should be empty */
8996  file_tempcache_free_entry_list (&file_Tempcache->tran_files[tran]);
8997  }
8998  }
8999  free_and_init (file_Tempcache->tran_files);
9000 
9001  /* temporary volumes are removed, we don't have to destroy files */
9004 
9005  file_tempcache_free_entry_list (&file_Tempcache->free_entries);
9006 
9008 
9009  pthread_mutex_destroy (&file_Tempcache->mutex);
9010 
9011  free_and_init (file_Tempcache);
9012 }
9013 
9014 /*
9015  * file_tempcache_free_entry_list () - free entry list and set it to NULL
9016  *
9017  * return : void
9018  * list (in/out) : list to free. it becomes NULL.
9019  */
9020 STATIC_INLINE void
9022 {
9023  FILE_TEMPCACHE_ENTRY *entry;
9024  FILE_TEMPCACHE_ENTRY *next;
9025 
9027 
9028  for (entry = *list; entry != NULL; entry = next)
9029  {
9030  next = entry->next;
9031  free (entry);
9032  }
9033  *list = NULL;
9034 }
9035 
9036 /*
9037  * file_tempcache_alloc_entry () - allocate a new file temporary cache entry
9038  *
9039  * return : error code
9040  * entry (out) : entry from free entries or newly allocated
9041  */
9042 STATIC_INLINE int
9044 {
9046 
9047  if (file_Tempcache->free_entries != NULL)
9048  {
9049  assert (file_Tempcache->nfree_entries > 0);
9050 
9051  *entry = file_Tempcache->free_entries;
9052  file_Tempcache->free_entries = file_Tempcache->free_entries->next;
9053  file_Tempcache->nfree_entries--;
9054  }
9055  else
9056  {
9057  *entry = (FILE_TEMPCACHE_ENTRY *) malloc (sizeof (FILE_TEMPCACHE_ENTRY));
9058  if (*entry == NULL)
9059  {
9061  return ER_OUT_OF_VIRTUAL_MEMORY;
9062  }
9063  }
9064 
9065  (*entry)->next = NULL;
9066  VFID_SET_NULL (&(*entry)->vfid);
9067  (*entry)->ftype = FILE_UNKNOWN_TYPE;
9068 
9069  return NO_ERROR;
9070 }
9071 
9072 /*
9073  * file_tempcache_retire_entry () - retire entry to free entry list (if not maxed) or deallocate
9074  *
9075  * return : void
9076  * entry (in) : retired entry
9077  */
9078 STATIC_INLINE void
9080 {
9081  /* we lock to change free entry list */
9083 
9084  if (file_Tempcache->nfree_entries < file_Tempcache->nfree_entries_max)
9085  {
9086  entry->next = file_Tempcache->free_entries;
9087  file_Tempcache->free_entries = entry;
9088  file_Tempcache->nfree_entries++;
9089  }
9090  else
9091  {
9092  free (entry);
9093  }
9094 
9096 }
9097 
9098 /*
9099  * file_tempcache_lock () - lock temporary cache mutex
9100  *
9101  * return : void
9102  */
9103 STATIC_INLINE void
9104 file_tempcache_lock (void)
9105 {
9106  assert (file_Tempcache->owner_mutex != thread_get_current_entry_index ());
9107  pthread_mutex_lock (&file_Tempcache->mutex);
9108  assert (file_Tempcache->owner_mutex == -1);
9109 #if !defined (NDEBUG)
9110  file_Tempcache->owner_mutex = thread_get_current_entry_index ();
9111 #endif /* !NDEBUG */
9112 }
9113 
9114 /*
9115  * file_tempcache_unlock () - unlock temporary cache mutex
9116  *
9117  * return : void
9118  */
9119 STATIC_INLINE void
9121 {
9122  assert (file_Tempcache->owner_mutex == thread_get_current_entry_index ());
9123 #if !defined (NDEBUG)
9124  file_Tempcache->owner_mutex = -1;
9125 #endif /* !NDEBUG */
9126  pthread_mutex_unlock (&file_Tempcache->mutex);
9127 }
9128 
9129 /*
9130  * file_tempcache_check_lock () - check temporary cache mutex is locked (for debug)
9131  *
9132  * return : void
9133  */
9134 STATIC_INLINE void
9136 {
9137  assert (file_Tempcache->owner_mutex == thread_get_current_entry_index ());
9138 }
9139 
9140 /*
9141  * file_tempcache_get () - get a file from temporary file cache
9142  *
9143  * return : error code
9144  * thread_p (in) : thread entry
9145  * ftype (in) : file type
9146  * numerable (in) : true for numerable file, false for regular file
9147  * entry (out) : always output an temporary cache entry. caller must check entry VFID to find if cached file was used
9148  */
9149 STATIC_INLINE int
9150 file_tempcache_get (THREAD_ENTRY * thread_p, FILE_TYPE ftype, bool numerable, FILE_TEMPCACHE_ENTRY ** entry)
9151 {
9152  int error_code = NO_ERROR;
9153 
9154  assert (entry != NULL && *entry == NULL);
9155 
9157 
9158  *entry = numerable ? file_Tempcache->cached_numerable : file_Tempcache->cached_not_numerable;
9159  if (*entry != NULL && (*entry)->ftype != ftype)
9160  {
9161  /* change type */
9162  error_code = file_temp_set_type (thread_p, &(*entry)->vfid, ftype);
9163  if (error_code != NO_ERROR)
9164  {
9165  /* could not change it, give up */
9166  *entry = NULL;
9167  }
9168  else
9169  {
9170  (*entry)->ftype = ftype;
9171  }
9172  }
9173 
9174  if (*entry != NULL)
9175  {
9176  /* remove from cache */
9177  if (numerable)
9178  {
9179  assert (*entry == file_Tempcache->cached_numerable);
9180  assert (file_Tempcache->ncached_numerable > 0);
9181 
9182  file_Tempcache->cached_numerable = file_Tempcache->cached_numerable->next;
9183  file_Tempcache->ncached_numerable--;
9184  }
9185  else
9186  {
9187  assert (*entry == file_Tempcache->cached_not_numerable);
9188  assert (file_Tempcache->ncached_not_numerable > 0);
9189 
9190  file_Tempcache->cached_not_numerable = file_Tempcache->cached_not_numerable->next;
9191  file_Tempcache->ncached_not_numerable--;
9192  }
9193 
9194  (*entry)->next = NULL;
9195 
9196  file_log ("file_tempcache_get",
9197  "found in cache temporary file entry "
9199  FILE_TEMPCACHE_ENTRY_AS_ARGS (*entry), numerable ? "numerable" : "regular", FILE_TEMPCACHE_AS_ARGS);
9200 
9202  return NO_ERROR;
9203  }
9204 
9205  /* not from cache, get a new entry */
9206  error_code = file_tempcache_alloc_entry (entry);
9207  if (error_code != NO_ERROR)
9208  {
9209  ASSERT_ERROR ();
9211  return error_code;
9212  }
9213 
9214  /* init new entry */
9215  assert (*entry != NULL);
9216  (*entry)->next = NULL;
9217  (*entry)->ftype = ftype;
9218  VFID_SET_NULL (&(*entry)->vfid);
9219 
9221 
9222  return NO_ERROR;
9223 }
9224 
9225 /*
9226  * file_tempcache_check_duplicate () - check file cache whether it already has the entry to be added
9227  *
9228  * return : true if file is already in file cache, otherwise false
9229  * thread_p (in) : thread entry
9230  * entry (in) : entry of temporary file to be added to file cache
9231  * is_numerable(in) : is numerable temporary file
9232  *
9233  * note it is a debugging function.
9234  */
9235 static bool
9236 file_tempcache_check_duplicate (THREAD_ENTRY * thread_p, FILE_TEMPCACHE_ENTRY * entry, bool is_numerable)
9237 {
9239 
9240  assert (entry != NULL);
9241  assert (!VFID_ISNULL (&entry->vfid));
9242 
9243  if (is_numerable)
9244  {
9245  for (p = file_Tempcache->cached_numerable; p != NULL; p = p->next)
9246  {
9247  if (VFID_EQ (&p->vfid, &entry->vfid))
9248  {
9249  assert (!VFID_EQ (&p->vfid, &entry->vfid));
9250  return true;
9251  }
9252  }
9253  }
9254  else
9255  {
9256  for (p = file_Tempcache->cached_not_numerable; p != NULL; p = p->next)
9257  {
9258  if (VFID_EQ (&p->vfid, &entry->vfid))
9259  {
9260  assert (!VFID_EQ (&p->vfid, &entry->vfid));
9261  return true;
9262  }
9263  }
9264  }
9265 
9266  return false;
9267 }
9268 
9269 /*
9270  * file_tempcache_put () - put entry to file cache (if cache is not full and if file passes vetting)
9271  *
9272  * return : true if file was cached, false otherwise
9273  * thread_p (in) : thread entry
9274  * entry (in) : entry of retired temporary file
9275  */
9276 STATIC_INLINE bool
9278 {
9279  FILE_HEADER fhead;
9280 
9281  assert (entry != NULL);
9282  assert (!VFID_ISNULL (&entry->vfid));
9283  assert (entry->next == NULL);
9284 
9285  fhead.n_page_user = -1;
9286  if (file_header_copy (thread_p, &entry->vfid, &fhead) != NO_ERROR
9288  {
9289  /* file not valid for cache */
9290  file_log ("file_tempcache_put",
9291  "could not cache temporary file " FILE_TEMPCACHE_ENTRY_MSG
9292  ", fhead->n_page_user = %d ", FILE_TEMPCACHE_ENTRY_AS_ARGS (entry), fhead.n_page_user);
9293  return false;
9294  }
9295  /* make sure entry has correct type. */
9296  entry->ftype = fhead.type;
9297 
9298  /* lock temporary cache */
9300 
9301  if (file_Tempcache->ncached_not_numerable + file_Tempcache->ncached_numerable < file_Tempcache->nfree_entries_max)
9302  {
9303  /* cache not full */
9304  assert ((file_Tempcache->cached_not_numerable == NULL) == (file_Tempcache->ncached_not_numerable == 0));
9305  assert ((file_Tempcache->cached_numerable == NULL) == (file_Tempcache->ncached_numerable == 0));
9306 
9307  /* reset file */
9308  if (file_temp_reset_user_pages (thread_p, &entry->vfid) != NO_ERROR)
9309  {
9310  /* failed to reset file, we cannot cache it */
9311  ASSERT_ERROR ();
9312 
9313  file_log ("file_tempcache_put",
9314  "could not cache temporary file " FILE_TEMPCACHE_ENTRY_MSG
9315  ", error during file reset", FILE_TEMPCACHE_ENTRY_AS_ARGS (entry));
9317  return false;
9318  }
9319 
9320  assert (file_tempcache_check_duplicate (thread_p, entry, FILE_IS_NUMERABLE (&fhead)) == false);
9321 
9322  /* add numerable temporary file to cached numerable file list, regular file to not numerable list */
9323  if (FILE_IS_NUMERABLE (&fhead))
9324  {
9325  entry->next = file_Tempcache->cached_numerable;
9326  file_Tempcache->cached_numerable = entry;
9327  file_Tempcache->ncached_numerable++;
9328  }
9329  else
9330  {
9331  entry->next = file_Tempcache->cached_not_numerable;
9332  file_Tempcache->cached_not_numerable = entry;
9333  file_Tempcache->ncached_not_numerable++;
9334  }
9335 
9336  file_log ("file_tempcache_put",
9337  "cached temporary file " FILE_TEMPCACHE_ENTRY_MSG ", %s\n"
9339  FILE_IS_NUMERABLE (&fhead) ? "numerable" : "regular", FILE_TEMPCACHE_AS_ARGS);
9340 
9342 
9343  /* cached */
9344  return true;
9345  }
9346  else
9347  {
9348  /* cache full */
9349  file_log ("file_tempcache_put",
9350  "could not cache temporary file " FILE_TEMPCACHE_ENTRY_MSG
9351  ", temporary cache is full \n" FILE_TEMPCACHE_MSG,
9354  return false;
9355  }
9356 }
9357 
9358 /*
9359  * file_get_tempcache_entry_index () - returns entry index of tempcache
9360  *
9361  * return : int
9362  * thread_p (in) : thread entry
9363  */
9364 STATIC_INLINE int
9366 {
9367 #if defined (SERVER_MODE)
9368  return logtb_get_current_tran_index ();
9369 #else
9370  return 0;
9371 #endif
9372 }
9373 
9374 /*
9375  * file_tempcache_drop_tran_temp_files () - drop all temporary files created by current transaction
9376  *
9377  * return : void
9378  * thread_p (in) : thread entry
9379  */
9380 void
9382 {
9383  if (file_Tempcache->tran_files[file_get_tempcache_entry_index (thread_p)] != NULL)
9384  {
9385  file_log ("file_tempcache_drop_tran_temp_files",
9386  "drop %d transaction temporary files", file_get_tran_num_temp_files (thread_p));
9388  &file_Tempcache->tran_files[file_get_tempcache_entry_index (thread_p)]);
9389  }
9390 }
9391 
9392 /*
9393  * file_tempcache_cache_or_drop_entries () - drop all temporary files in the give entry list
9394  *
9395  * return : void
9396  * thread_p (in) : thread entry
9397  * entries (in) : temporary files entry list
9398  */
9399 STATIC_INLINE void
9401 {
9402  FILE_TEMPCACHE_ENTRY *temp_file;
9403  FILE_TEMPCACHE_ENTRY *next = NULL;
9404 
9405  for (temp_file = *entries; temp_file != NULL; temp_file = next)
9406  {
9407  next = temp_file->next;
9408  temp_file->next = NULL;
9409 
9410  if (!file_tempcache_put (thread_p, temp_file))
9411  {
9412  /* was not cached. destroy the file */
9413  file_log ("file_tempcache_cache_or_drop_entries",
9414  "drop entry " FILE_TEMPCACHE_ENTRY_MSG, FILE_TEMPCACHE_ENTRY_AS_ARGS (temp_file));
9415  if (file_destroy (thread_p, &temp_file->vfid, true) != NO_ERROR)
9416  {
9417  /* file is leaked */
9418  assert_release (false);
9419  /* ignore error and continue free as many files as possible */
9420  }
9421  file_tempcache_retire_entry (temp_file);
9422  }
9423  }
9424  *entries = NULL;
9425 }
9426 
9427 /*
9428  * file_tempcache_pop_tran_file () - pop entry with the given VFID from transaction list
9429  *
9430  * return : popped entry
9431  * thread_p (in) : thread entry
9432  * vfid (in) : file identifier
9433  */
9436 {
9437  FILE_TEMPCACHE_ENTRY **tran_files_p = &file_Tempcache->tran_files[file_get_tempcache_entry_index (thread_p)];
9438  FILE_TEMPCACHE_ENTRY *entry = NULL, *prev_entry = NULL;
9439 
9440  for (entry = *tran_files_p; entry != NULL; entry = entry->next)
9441  {
9442  if (VFID_EQ (&entry->vfid, vfid))
9443  {
9444  /* remove entry from transaction list */
9445  if (prev_entry != NULL)
9446  {
9447  prev_entry->next = entry->next;
9448  }
9449  else
9450  {
9451  *tran_files_p = entry->next;
9452  }
9453  entry->next = NULL;
9454 
9455  file_log ("file_tempcache_pop_tran_file", "removed entry " FILE_TEMPCACHE_ENTRY_MSG,
9457 
9458  return entry;
9459  }
9460  prev_entry = entry;
9461  }
9462 
9463  /* should have found it */
9464  assert_release (false);
9465  return NULL;
9466 }
9467 
9468 /*
9469  * file_tempcache_push_tran_file () - push temporary file entry to transaction list
9470  *
9471  * return : void
9472  * thread_p (in) : thread entry
9473  * entry (in) : temporary cache entry
9474  */
9475 STATIC_INLINE void
9477 {
9478  FILE_TEMPCACHE_ENTRY **tran_files_p = &file_Tempcache->tran_files[file_get_tempcache_entry_index (thread_p)];
9479 
9480  entry->next = *tran_files_p;
9481  *tran_files_p = entry;
9482 
9483  file_log ("file_tempcache_push_tran_file", "pushed entry " FILE_TEMPCACHE_ENTRY_MSG,
9485 }
9486 
9487 /*
9488  * file_get_tran_num_temp_files () - returns the number of temp file entries of the given transaction
9489  *
9490  * return : the number of temp files of the given transaction
9491  * thread_p (in) : thread entry
9492  */
9493 int
9495 {
9496  FILE_TEMPCACHE_ENTRY **tran_files_p = &file_Tempcache->tran_files[file_get_tempcache_entry_index (thread_p)];
9497  FILE_TEMPCACHE_ENTRY *entry;
9498  int num = 0;
9499 
9500  for (entry = *tran_files_p; entry != NULL; entry = entry->next)
9501  {
9502  num++;
9503  }
9504  return num;
9505 }
9506 
9507 /*
9508  * file_tempcache_dump () - dump temporary files cache
9509  *
9510  * return : void
9511  * fp (in) : dump output
9512  */
9513 STATIC_INLINE void
9515 {
9516  FILE_TEMPCACHE_ENTRY *cached_files;
9517 
9519 
9520  fprintf (fp, "DUMPING file manager's temporary files cache.\n");
9521  fprintf (fp,
9522  " max files = %d, regular files count = %d, numerable files count = %d.\n\n",
9523  file_Tempcache->ncached_max, file_Tempcache->ncached_not_numerable, file_Tempcache->ncached_numerable);
9524 
9525  if (file_Tempcache->cached_not_numerable != NULL)
9526  {
9527  fprintf (fp, " cached regular files: \n");
9528  for (cached_files = file_Tempcache->cached_not_numerable; cached_files != NULL; cached_files = cached_files->next)
9529  {
9530  fprintf (fp, " VFID = %d|%d, file type = %s \n",
9531  VFID_AS_ARGS (&cached_files->vfid), file_type_to_string (cached_files->ftype));
9532  }
9533  fprintf (fp, "\n");
9534  }
9535  if (file_Tempcache->cached_numerable != NULL)
9536  {
9537  fprintf (fp, " cached numerable files: \n");
9538  for (cached_files = file_Tempcache->cached_numerable; cached_files != NULL; cached_files = cached_files->next)
9539  {
9540  fprintf (fp, " VFID = %d|%d, file type = %s \n",
9541  VFID_AS_ARGS (&cached_files->vfid), file_type_to_string (cached_files->ftype));
9542  }
9543  fprintf (fp, "\n");
9544  }
9545 
9547 
9548  /* todo: to print transaction temporary files we need some kind of synchronization... right now each transaction
9549  * manages its own list freely. */
9550 }
9551 
9552 /************************************************************************/
9553 /* File tracker section */
9554 /************************************************************************/
9555 
9556 /*
9557  * file_tracker_create () - create file tracker.
9558  *
9559  * return : error code
9560  * thread_p (in) : thread entry
9561  * vfid_tracker_out (out) : file tracker VFID
9562  */
9563 int
9564 file_tracker_create (THREAD_ENTRY * thread_p, VFID * vfid_tracker_out)
9565 {
9566  int error_code = NO_ERROR;
9567 
9568  /* start sys op */
9569  log_sysop_start (thread_p);
9570 
9571  error_code = file_create_with_npages (thread_p, FILE_TRACKER, 1, NULL, vfid_tracker_out);
9572  if (error_code != NO_ERROR)
9573  {
9574  ASSERT_ERROR ();
9575  goto exit;
9576  }
9577  error_code = file_alloc_sticky_first_page (thread_p, vfid_tracker_out, file_tracker_init_page, NULL,
9578  &file_Tracker_vpid, NULL);
9579  if (error_code != NO_ERROR)
9580  {
9581  ASSERT_ERROR ();
9582  goto exit;
9583  }
9584 
9585  /* success */
9586  assert (error_code == NO_ERROR);
9587 
9588 exit:
9589 
9590  if (error_code != NO_ERROR)
9591  {
9592  log_sysop_abort (thread_p);
9593  VFID_SET_NULL (vfid_tracker_out);
9594  VPID_SET_NULL (&file_Tracker_vpid);
9595  }
9596  else
9597  {
9598  log_sysop_commit (thread_p);
9599 
9600  VFID_COPY (&file_Tracker_vfid, vfid_tracker_out);
9601  }
9602  return error_code;
9603 }
9604 
9605 /*
9606  * file_tracker_load () - load file tracker
9607  *
9608  * return : error code
9609  * thread_p (in) : thread entry
9610  * vfid (in) : file tracker file identifier
9611  */
9612 int
9613 file_tracker_load (THREAD_ENTRY * thread_p, const VFID * vfid)
9614 {
9615  int error_code = NO_ERROR;
9616 
9617  assert (vfid != NULL && !VFID_ISNULL (vfid));
9618 
9619  error_code = file_get_sticky_first_page (thread_p, vfid, &file_Tracker_vpid);
9620  if (error_code != NO_ERROR)
9621  {
9622  ASSERT_ERROR ();
9623  return error_code;
9624  }
9625 
9626  file_Tracker_vfid = *vfid;
9627 
9628  return NO_ERROR;
9629 }
9630 
9631 /*
9632  * file_tracker_init_page () - initialize new file tracker page
9633  *
9634  * return : NO_ERROR
9635  * thread_p (in) : thread entry
9636  * page (in) : new page
9637  * args (in) : ignored
9638  */
9639 static int
9640 file_tracker_init_page (THREAD_ENTRY * thread_p, PAGE_PTR page, void *args)
9641 {
9642  FILE_EXTENSIBLE_DATA *extdata = (FILE_EXTENSIBLE_DATA *) page;
9643 
9644  pgbuf_set_page_ptype (thread_p, page, PAGE_FTAB);
9645  file_extdata_init (sizeof (FILE_TRACK_ITEM), DB_PAGESIZE, extdata);
9646  log_append_undoredo_data2 (thread_p, RVPGBUF_NEW_PAGE, NULL, page, (PGLENGTH) PAGE_FTAB, 0, sizeof (*extdata), NULL,
9647  page);
9648  pgbuf_set_dirty (thread_p, page, DONT_FREE);
9649 
9650  return NO_ERROR;
9651 }
9652 
9653 /*
9654  * file_tracker_register () - register new file in file tracker
9655  *
9656  * return : error code
9657  * thread_p (in) : thread entry
9658  * vfid (in) : file identifier
9659  * ftype (in) : file type
9660  * metadata (in) : meta-data about file (if NULL will be initialized as 0).
9661  */
9662 static int
9663 file_tracker_register (THREAD_ENTRY * thread_p, const VFID * vfid, FILE_TYPE ftype, FILE_TRACK_METADATA * metadata)
9664 {
9665  FILE_TRACK_ITEM item;
9666  PAGE_PTR page_track_head = NULL;
9667  int error_code = NO_ERROR;
9668 
9669  assert (vfid != NULL);
9670  assert (sizeof (item.metadata) == sizeof (item.metadata.metadata_size_tracker));
9671  assert (!VPID_ISNULL (&file_Tracker_vpid));
9673 
9674  item.volid = vfid->volid;
9675  item.fileid = vfid->fileid;
9676  item.type = (INT16) ftype;
9677 
9678  if (metadata == NULL)
9679  {
9680  /* set 0 */
9682  }
9683  else
9684  {
9685  /* set given metadata */
9686  item.metadata = *metadata;
9687  }
9688 
9689  page_track_head = pgbuf_fix (thread_p, &file_Tracker_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
9690  if (page_track_head == NULL)
9691  {
9692  ASSERT_ERROR_AND_SET (error_code);
9693  return error_code;
9694  }
9695 
9696  error_code = file_tracker_register_internal (thread_p, page_track_head, &item);
9697  if (error_code != NO_ERROR)
9698  {
9699  ASSERT_ERROR ();
9700  }
9701 
9702  /* unfix head */
9703  pgbuf_unfix (thread_p, page_track_head);
9704 
9705  /* return error code */
9706  return error_code;
9707 }
9708 
9709 /*
9710  * file_tracker_register_internal () - register new file in file tracker internal function. called by register and
9711  * unregister undo.
9712  *
9713  * return : error code
9714  * thread_p (in) : thread entry
9715  * page_track_head (in) : tracker header page
9716  * item (in) : item (with file data)
9717  */
9718 static int
9719 file_tracker_register_internal (THREAD_ENTRY * thread_p, PAGE_PTR page_track_head, const FILE_TRACK_ITEM * item)
9720 {
9721  FILE_EXTENSIBLE_DATA *extdata = NULL;
9722  PAGE_PTR page_track_other = NULL;
9723  PAGE_PTR page_extdata = NULL;
9724  bool found;
9725  int pos;
9726  LOG_LSA save_lsa;
9727  int error_code = NO_ERROR;
9728 
9730 
9731  /* find a space to add new item */
9732  extdata = (FILE_EXTENSIBLE_DATA *) page_track_head;
9733  error_code = file_extdata_find_not_full (thread_p, &extdata, &page_track_other, &found);
9734  if (error_code != NO_ERROR)
9735  {
9736  ASSERT_ERROR ();
9737  goto exit;
9738  }
9739  page_extdata = page_track_other != NULL ? page_track_other : page_track_head;
9740 
9741  if (!found)
9742  {
9743  /* allocate a new page */
9744  VPID vpid_new_page;
9745 
9746  error_code = file_alloc (thread_p, &file_Tracker_vfid, file_tracker_init_page, NULL, &vpid_new_page, NULL);
9747  if (error_code != NO_ERROR)
9748  {
9749  ASSERT_ERROR ();
9750  goto exit;
9751  }
9752 
9753  /* add link to new page */
9754  file_log_extdata_set_next (thread_p, extdata, page_extdata, &vpid_new_page);
9755  extdata->vpid_next = vpid_new_page;
9756  pgbuf_set_dirty (thread_p, page_extdata, DONT_FREE);
9757 
9758  if (page_track_other != NULL)
9759  {
9760  /* no longer needed */
9761  pgbuf_unfix_and_init (thread_p, page_track_other);
9762  }
9763 
9764  /* initialize new page */
9765  page_track_other = pgbuf_fix (thread_p, &vpid_new_page, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
9766  if (page_track_other == NULL)
9767  {
9768  ASSERT_ERROR_AND_SET (error_code);
9769  goto exit;
9770  }
9771  assert (pgbuf_get_page_ptype (thread_p, page_track_other) == PAGE_FTAB);
9772 
9773  page_extdata = page_track_other;
9774  extdata = (FILE_EXTENSIBLE_DATA *) page_extdata;
9775  }
9776 
9777  assert (page_extdata != NULL);
9778  assert (extdata != NULL);
9779  assert (extdata == (FILE_EXTENSIBLE_DATA *) page_extdata);
9780  assert (!file_extdata_is_full (extdata));
9781 
9782  file_extdata_find_ordered (extdata, item, file_compare_track_items, &found, &pos);
9783  if (found)
9784  {
9785  /* impossible */
9786  assert_release (false);
9787  error_code = ER_FAILED;
9788  goto exit;
9789  }
9790 
9791  save_lsa = *pgbuf_get_lsa (page_extdata);
9792  file_extdata_insert_at (extdata, pos, 1, item);
9793  file_log_extdata_add (thread_p, extdata, page_extdata, pos, 1, item);
9794  pgbuf_set_dirty (thread_p, page_extdata, DONT_FREE);
9795 
9796  file_log ("file_tracker_register_internal", "added " FILE_TRACK_ITEM_MSG ", to page %d|%d, prev_lsa = %lld|%d, "
9797  "crt_lsa = %lld|%d, at pos %d ", FILE_TRACK_ITEM_AS_ARGS (item),
9798  PGBUF_PAGE_MODIFY_ARGS (page_extdata, &save_lsa), pos);
9799 
9800 exit:
9801  if (page_track_other != NULL)
9802  {
9803  pgbuf_unfix (thread_p, page_track_other);
9804  }
9805  return error_code;
9806 }
9807 
9808 /*
9809  * file_tracker_unregister () - unregister file from tracker
9810  *
9811  * return : error code
9812  * thread_p (in) : thread entry
9813  * vfid (in) : file identifier
9814  */
9815 static int
9816 file_tracker_unregister (THREAD_ENTRY * thread_p, const VFID * vfid)
9817 {
9818  PAGE_PTR page_track_head = NULL;
9819  FILE_EXTENSIBLE_DATA *extdata = NULL;
9820  FILE_TRACK_ITEM item_inout;
9821  VPID vpid_merged = VPID_INITIALIZER;
9822  int error_code = NO_ERROR;
9823 
9824  assert (vfid != NULL && !VFID_ISNULL (vfid));
9826 
9827  page_track_head = pgbuf_fix (thread_p, &file_Tracker_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
9828  if (page_track_head == NULL)
9829  {
9830  ASSERT_ERROR_AND_SET (error_code);
9831  return error_code;
9832  }
9833  extdata = (FILE_EXTENSIBLE_DATA *) page_track_head;
9834 
9835  /* we still need to start a system op. */
9836  log_sysop_start (thread_p);
9837 
9838  item_inout.volid = vfid->volid;
9839  item_inout.fileid = vfid->fileid;
9840 
9841  error_code = file_extdata_find_and_remove_item (thread_p, extdata, page_track_head, &item_inout,
9842  file_compare_track_items, true, &item_inout, &vpid_merged);
9843  if (error_code != NO_ERROR)
9844  {
9845  ASSERT_ERROR ();
9846  goto exit;
9847  }
9848 
9849  if (!VPID_ISNULL (&vpid_merged))
9850  {
9851  /* merged page. deallocate it */
9852  file_log ("file_tracker_unregister", "deallocate page %d|%d ", VPID_AS_ARGS (&vpid_merged));
9853 
9854  error_code = file_dealloc (thread_p, &file_Tracker_vfid, &vpid_merged, FILE_TRACKER);
9855  if (error_code != NO_ERROR)
9856  {
9857  ASSERT_ERROR ();
9858  goto exit;
9859  }
9860  }
9861 
9862  /* success */
9863  assert (error_code == NO_ERROR);
9864 
9865 exit:
9866  if (error_code != NO_ERROR)
9867  {
9868  log_sysop_abort (thread_p);
9869  }
9870  else
9871  {
9872  log_sysop_end_logical_undo (thread_p, RVFL_TRACKER_UNREGISTER, NULL, sizeof (item_inout), (char *) &item_inout);
9873  }
9874  if (page_track_head != NULL)
9875  {
9876  pgbuf_unfix (thread_p, page_track_head);
9877  }
9878  return error_code;
9879 }
9880 
9881 /*
9882  * file_rv_tracker_unregister_undo () - undo the unregister of file. may happen if file_destroy is only partially
9883  * executed. since data inside tracker moved from page to page, the unregister
9884  * operation is logged using system ops with logical undo/compensate.
9885  *
9886  * return : error code
9887  * thread_p (in) : thread entry
9888  * rcv (in) : recovery data
9889  */
9890 int
9892 {
9893  PAGE_PTR page_track_head;
9894  int error_code = NO_ERROR;
9895 
9896  assert (rcv->length == sizeof (FILE_TRACK_ITEM));
9897 
9898  page_track_head = pgbuf_fix (thread_p, &file_Tracker_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
9899  if (page_track_head == NULL)
9900  {
9901  assert (false);
9902  return ER_FAILED;
9903  }
9904 
9905  log_sysop_start (thread_p);
9906 
9907  /* undo unregister => register the logged item */
9908  error_code = file_tracker_register_internal (thread_p, page_track_head, (FILE_TRACK_ITEM *) rcv->data);
9909  if (error_code != NO_ERROR)
9910  {
9911  /* not expected */
9912  assert (false);
9913 
9914  log_sysop_abort (thread_p);
9915  }
9916  else
9917  {
9918  /* need to finish system op while holding latch on header */
9920  }
9921 
9922  pgbuf_unfix_and_init (thread_p, page_track_head);
9923 
9924  return error_code;
9925 }
9926 
9927 /*
9928  * file_tracker_apply_to_file () - search for file tracker item and apply function
9929  *
9930  * return : error code
9931  * thread_p (in) : thread entry
9932  * vfid (in) : file identifier
9933  * mode (in) : latch mode for tracker pages
9934  * func (in) : apply function for found item
9935  * args (in) : arguments for applied function
9936  */
9937 static int
9939  FILE_TRACK_ITEM_FUNC func, void *args)
9940 {
9941  PAGE_PTR page_track_head = NULL;
9942  PAGE_PTR page_track_other = NULL;
9943  FILE_EXTENSIBLE_DATA *extdata;
9944  FILE_TRACK_ITEM item_search;
9945  bool for_write = (mode == PGBUF_LATCH_WRITE);
9946  bool found = false;
9947  int pos = -1;
9948  int error_code = NO_ERROR;
9949 
9950  assert (func != NULL);
9951  assert (mode == PGBUF_LATCH_READ || mode == PGBUF_LATCH_WRITE);
9952 
9953  page_track_head = pgbuf_fix (thread_p, &file_Tracker_vpid, OLD_PAGE, mode, PGBUF_UNCONDITIONAL_LATCH);
9954  if (page_track_head == NULL)
9955  {
9956  ASSERT_ERROR_AND_SET (error_code);
9957  return error_code;
9958  }
9959  extdata = (FILE_EXTENSIBLE_DATA *) page_track_head;
9960 
9961  item_search.volid = vfid->volid;
9962  item_search.fileid = vfid->fileid;
9963  error_code = file_extdata_search_item (thread_p, &extdata, &item_search, file_compare_track_items, true, for_write,
9964  &found, &pos, &page_track_other);
9965  if (error_code != NO_ERROR)
9966  {
9967  ASSERT_ERROR ();
9968  goto exit;
9969  }
9970  if (!found)
9971  {
9972  assert_release (false);
9973  error_code = ER_FAILED;
9974  goto exit;
9975  }
9976 
9977  error_code = func (thread_p, page_track_other != NULL ? page_track_other : page_track_head, extdata, pos, NULL, args);
9978  if (error_code != NO_ERROR)
9979  {
9980  ASSERT_ERROR ();
9981  goto exit;
9982  }
9983 
9984  /* success */
9985  assert (error_code == NO_ERROR);
9986 
9987 exit:
9988  if (page_track_other != NULL)
9989  {
9990  pgbuf_unfix (thread_p, page_track_other);
9991  }
9992  if (page_track_head != NULL)
9993  {
9994  pgbuf_unfix (thread_p, page_track_head);
9995  }
9996  return error_code;
9997 }
9998 
9999 /*
10000  * file_tracker_map () - map item function to all tracked files
10001  *
10002  * return : error code
10003  * thread_p (in) : thread entry
10004  * latch_mode (in) : latch mode
10005  * func (in) : function called for each item
10006  * args (in) : arguments for function
10007  */
10008 static int
10009 file_tracker_map (THREAD_ENTRY * thread_p, PGBUF_LATCH_MODE latch_mode, FILE_TRACK_ITEM_FUNC func, void *args)
10010 {
10011  PAGE_PTR page_track_head = NULL;
10012  PAGE_PTR page_track_other = NULL;
10013  PAGE_PTR page_extdata = NULL;
10014  FILE_EXTENSIBLE_DATA *extdata;
10015  VPID vpid_next = VPID_INITIALIZER;
10016  bool stop = false;
10017  int index_item;
10018  int error_code = NO_ERROR;
10019 
10020  page_track_head = pgbuf_fix (thread_p, &file_Tracker_vpid, OLD_PAGE, latch_mode, PGBUF_UNCONDITIONAL_LATCH);
10021  if (page_track_head == NULL)
10022  {
10023  ASSERT_ERROR_AND_SET (error_code);
10024  return error_code;
10025  }
10026 
10027  page_extdata = page_track_head;
10028  while (true)
10029  {
10030  extdata = (FILE_EXTENSIBLE_DATA *) page_extdata;
10031  for (index_item = 0; index_item < file_extdata_item_count (extdata); index_item++)
10032  {
10033  error_code = func (thread_p, page_extdata, extdata, index_item, &stop, args);
10034  if (error_code != NO_ERROR)
10035  {
10036  ASSERT_ERROR ();
10037  goto exit;
10038  }
10039  if (stop)
10040  {
10041  /* early out */
10042  goto exit;
10043  }
10044  }
10045 
10046  vpid_next = extdata->vpid_next;
10047  if (page_track_other != NULL)
10048  {
10049  pgbuf_unfix_and_init (thread_p, page_track_other);
10050  }
10051  if (VPID_ISNULL (&vpid_next))
10052  {
10053  break;
10054  }
10055 
10056  page_track_other = pgbuf_fix (thread_p, &vpid_next, OLD_PAGE, latch_mode, PGBUF_UNCONDITIONAL_LATCH);
10057  if (page_track_other == NULL)
10058  {
10059  ASSERT_ERROR_AND_SET (error_code);
10060  goto exit;
10061  }
10062 
10063  page_extdata = page_track_other;
10064  }
10065 
10066  /* success */
10067  assert (error_code == NO_ERROR);
10068 
10069 exit:
10070  if (page_track_other != NULL)
10071  {
10072  pgbuf_unfix (thread_p, page_track_other);
10073  }
10074  if (page_track_head != NULL)
10075  {
10076  pgbuf_unfix (thread_p, page_track_head);
10077  }
10078  return error_code;
10079 }
10080 
10081 /*
10082  * file_rv_tracker_reuse_heap () - recover reuse heap file in tracker
10083  *
10084  * return : NO_ERROR
10085  * thread_p (in) : thread entry
10086  * rcv (in) : recovery data
10087  */
10088 int
10090 {
10091  FILE_EXTENSIBLE_DATA *extdata = NULL;
10092  FILE_TRACK_ITEM *item = NULL;
10093 
10094  assert (rcv->length == 0);
10095  assert (rcv->pgptr != NULL);
10096  assert (rcv->offset >= 0);
10097 
10098  extdata = (FILE_EXTENSIBLE_DATA *) rcv->pgptr;
10099  assert (rcv->offset < file_extdata_item_count (extdata));
10100 
10101  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, rcv->offset);
10102  assert (item->type == FILE_HEAP);
10104 
10105  item->metadata.heap.is_marked_deleted = false;
10106 
10107  file_log ("file_rv_tracker_reuse_heap", "recovery reuse heap " FILE_TRACK_ITEM_MSG ", in "
10108  PGBUF_PAGE_STATE_MSG ("tracker page"), FILE_TRACK_ITEM_AS_ARGS (item), PGBUF_PAGE_STATE_ARGS (rcv->pgptr));
10109 
10110  pgbuf_set_dirty (thread_p, rcv->pgptr, DONT_FREE);
10111  return NO_ERROR;
10112 }
10113 
10114 /*
10115  * file_tracker_item_reuse_heap () - reuse heap file if marked as deleted. at the same time, update file descriptor in
10116  * file header (descriptor update must happen with tracker protection to provide
10117  * consistent checks).s
10118  *
10119  * return : error code
10120  * thread_p (in) : thread entry
10121  * page_of_item (in) : page of item
10122  * extdata (in) : extensible data
10123  * index_item (in) : index of item
10124  * args (in/out) : FILE_TRACKER_REUSE_HEAP_CONTEXT *
10125  */
10126 static int
10128  int index_item, bool * stop, void *args)
10129 {
10130  FILE_TRACK_ITEM *item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
10132  LOG_LSA save_lsa;
10133  VPID vpid_fhead;
10134  PAGE_PTR page_fhead = NULL;
10135  FILE_HEADER *fhead = NULL;
10136  FILE_DESCRIPTORS des_new;
10137  int error_code = NO_ERROR;
10138 #if defined (SERVER_MODE)
10139  bool is_dropped = false;
10140 #endif
10141 
10143 
10144  if (item->type != (INT16) FILE_HEAP)
10145  {
10146  return NO_ERROR;
10147  }
10148  if (!item->metadata.heap.is_marked_deleted)
10149  {
10150  return NO_ERROR;
10151  }
10152 
10153  /* get vfid */
10154  context->hfid_out->vfid.volid = item->volid;
10155  context->hfid_out->vfid.fileid = item->fileid;
10156 
10157 #if defined (SERVER_MODE)
10158  /* we need it to check vacuum won't consider this dropped. */
10159  error_code = vacuum_is_file_dropped (thread_p, &is_dropped, &context->hfid_out->vfid,
10160  logtb_get_current_mvccid (thread_p));
10161  if (error_code != NO_ERROR)
10162  {
10163  ASSERT_ERROR ();
10164  VFID_SET_NULL (&context->hfid_out->vfid);
10165  return error_code;
10166  }
10167  if (is_dropped)
10168  {
10169  file_log ("file_tracker_item_reuse_heap", "can't reuse heap file %d|%d with mvccid %llu because vacuum thinks it "
10170  "is dropped.\n", VFID_AS_ARGS (&context->hfid_out->vfid),
10171  (unsigned long long) logtb_get_current_mvccid (thread_p));
10172  VFID_SET_NULL (&context->hfid_out->vfid);
10173  return NO_ERROR;
10174  }
10175 #endif
10176 
10177  /* reuse this heap. but we need to update its descriptor first. */
10178  FILE_GET_HEADER_VPID (&context->hfid_out->vfid, &vpid_fhead);
10179  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
10180  if (page_fhead == NULL)
10181  {
10182  ASSERT_ERROR_AND_SET (error_code);
10183  goto exit;
10184  }
10185  fhead = (FILE_HEADER *) page_fhead;
10186  assert (fhead->type == FILE_HEAP || fhead->type == FILE_HEAP_REUSE_SLOTS);
10187  assert (VFID_EQ (&context->hfid_out->vfid, &fhead->self));
10188  assert (VFID_EQ (&context->hfid_out->vfid, &fhead->descriptor.heap.hfid.vfid));
10189  file_header_sanity_check (thread_p, fhead);
10190 
10191  /* get hfid */
10192  *context->hfid_out = fhead->descriptor.heap.hfid;
10193 #if !defined (NDEBUG)
10194  {
10195  /* safeguard: check hfid & sticky first page match */
10196  VPID vpid_heap_header = VPID_INITIALIZER;
10197  error_code = file_get_sticky_first_page (thread_p, &context->hfid_out->vfid, &vpid_heap_header);
10198  if (error_code != NO_ERROR)
10199  {
10200  ASSERT_ERROR ();
10201  goto exit;
10202  }
10203  assert (context->hfid_out->vfid.volid == vpid_heap_header.volid);
10204  assert (context->hfid_out->hpgid == vpid_heap_header.pageid);
10205  }
10206 #endif /* !NDEBUG */
10207 
10208  /* log & update class_oid */
10209  des_new = fhead->descriptor;
10210  des_new.heap.class_oid = context->class_oid;
10211  log_append_undoredo_data2 (thread_p, RVFL_FILEDESC_UPD, NULL, page_fhead,
10212  (PGLENGTH) ((char *) &fhead->descriptor - page_fhead), sizeof (fhead->descriptor),
10213  sizeof (des_new), &fhead->descriptor, &des_new);
10214  fhead->descriptor = des_new;
10215  pgbuf_set_dirty_and_free (thread_p, page_fhead);
10216 
10217  /* now update mark deleted flag in tracker item */
10218  save_lsa = *pgbuf_get_lsa (page_of_item);
10219 
10220  item->metadata.heap.is_marked_deleted = false;
10221  log_append_undoredo_data2 (thread_p, RVFL_TRACKER_HEAP_REUSE, NULL, page_of_item, index_item,
10222  sizeof (context->hfid_out->vfid), 0, &context->hfid_out->vfid, NULL);
10223  pgbuf_set_dirty (thread_p, page_of_item, DONT_FREE);
10224 
10225  file_log ("file_tracker_item_reuse_heap", "reuse heap file %d|%d; tracker page %d|%d, prev_lsa = %lld|%d, "
10226  "crt_lsa = %lld|%d, item at pos %d ", VFID_AS_ARGS (&context->hfid_out->vfid),
10227  PGBUF_PAGE_MODIFY_ARGS (page_of_item, &save_lsa), index_item);
10228 
10229  /* stop looking */
10230  *stop = true;
10231  assert (error_code == NO_ERROR);
10232 
10233 exit:
10234  if (page_fhead != NULL)
10235  {
10236  pgbuf_unfix (thread_p, page_fhead);
10237  }
10238  return error_code;
10239 }
10240 
10241 /*
10242  * file_tracker_reuse_heap () - search for heap file marked as deleted and reuse.
10243  *
10244  * return : error code
10245  * thread_p (in) : thread entry
10246  * class_oid (in) : class identifier for new heap file
10247  * hfid_out (out) : HFID of reused file or NULL HFID if no file was found
10248  *
10249  * note: file descriptor will also be updated if heap file is reused
10250  */
10251 int
10252 file_tracker_reuse_heap (THREAD_ENTRY * thread_p, const OID * class_oid, HFID * hfid_out)
10253 {
10255 
10256  assert (hfid_out != NULL);
10257  assert (class_oid != NULL);
10258 
10259  HFID_SET_NULL (hfid_out);
10260  context.hfid_out = hfid_out;
10261  context.class_oid = *class_oid;
10262 
10263  return file_tracker_map (thread_p, PGBUF_LATCH_WRITE, file_tracker_item_reuse_heap, &context);
10264 }
10265 
10266 /*
10267  * file_tracker_item_mark_heap_deleted () - FILE_TRACK_ITEM_FUNC to mark heap entry as deleted
10268  *
10269  * return : error code
10270  * thread_p (in) : thread entry
10271  * page_of_item (in) : page of item
10272  * extdata (in) : extensible data
10273  * index_item (in) : index of item
10274  * stop (in) : not used
10275  * args (in) : FILE_TRACK_MARK_HEAP_DELETED_CONTEXT *
10276  */
10277 static int
10279  int index_item, bool * stop, void *args)
10280 {
10281  FILE_TRACK_ITEM *item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
10283  LOG_LSA save_lsa;
10284 
10285  assert ((FILE_TYPE) item->type == FILE_HEAP);
10287 
10288  item->metadata.heap.is_marked_deleted = true;
10289 
10290  save_lsa = *pgbuf_get_lsa (page_of_item);
10291  if (context->is_undo)
10292  {
10294  pgbuf_get_vpid_ptr (page_of_item), index_item, page_of_item, 0, NULL,
10295  LOG_FIND_CURRENT_TDES (thread_p), &context->ref_lsa);
10296  }
10297  else
10298  {
10300  addr.pgptr = page_of_item;
10301  addr.offset = index_item;
10303  0, NULL, &context->ref_lsa);
10304  }
10305  pgbuf_set_dirty (thread_p, page_of_item, DONT_FREE);
10306 
10307  file_log ("file_tracker_item_mark_heap_deleted", "mark delete heap file %d|%d; "
10308  PGBUF_PAGE_MODIFY_MSG ("tracker page") ", item at pos %d, on %s, ref_lsa = %lld|%d",
10309  item->volid, item->fileid, PGBUF_PAGE_MODIFY_ARGS (page_of_item, &save_lsa), index_item,
10310  context->is_undo ? "undo" : "postpone", LSA_AS_ARGS (&context->ref_lsa));
10311 
10312  return NO_ERROR;
10313 }
10314 
10315 /*
10316  * file_rv_tracker_mark_heap_deleted () - search for heap file and mark it for delete
10317  *
10318  * return : error code
10319  * thread_p (in) : thread entry
10320  * rcv (in) : recovery data
10321  * is_undo (in) : true if called on undo/rollback, false if called on postpone
10322  */
10323 int
10324 file_rv_tracker_mark_heap_deleted (THREAD_ENTRY * thread_p, LOG_RCV * rcv, bool is_undo)
10325 {
10326  VFID *vfid = (VFID *) rcv->data;
10328  int error_code = NO_ERROR;
10329 
10330  assert (rcv->length == sizeof (*vfid));
10331  assert (!LSA_ISNULL (&rcv->reference_lsa));
10332 
10333  context.is_undo = is_undo;
10334  context.ref_lsa = rcv->reference_lsa;
10335 
10337  &context);
10338  if (error_code != NO_ERROR)
10339  {
10340  assert_release (false);
10341  }
10342 
10343  return error_code;
10344 }
10345 
10346 /*
10347  * file_rv_tracker_mark_heap_deleted_compensate_or_run_postpone () - used for recovery as compensate or run postpone
10348  * when heap file is marked as deleted.
10349  *
10350  * return : NO_ERROR
10351  * thread_p (in) : thread entry
10352  * rcv (in) : recovery data
10353  */
10354 int
10356 {
10357  FILE_EXTENSIBLE_DATA *extdata = NULL;
10358  FILE_TRACK_ITEM *item = NULL;
10359 
10360  assert (rcv->length == 0);
10361  assert (rcv->pgptr != NULL);
10362  assert (rcv->offset >= 0);
10363 
10364  extdata = (FILE_EXTENSIBLE_DATA *) rcv->pgptr;
10365  assert (rcv->offset < file_extdata_item_count (extdata));
10366 
10367  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, rcv->offset);
10368  assert (item->type == FILE_HEAP);
10370 
10371  item->metadata.heap.is_marked_deleted = true;
10372 
10373  file_log ("file_rv_tracker_mark_heap_deleted_compensate_or_run_postpone", "mark heap deleted" FILE_TRACK_ITEM_MSG
10374  ", in " PGBUF_PAGE_STATE_MSG ("tracker page"), FILE_TRACK_ITEM_AS_ARGS (item),
10375  PGBUF_PAGE_STATE_ARGS (rcv->pgptr));
10376 
10377  pgbuf_set_dirty (thread_p, rcv->pgptr, DONT_FREE);
10378  return NO_ERROR;
10379 }
10380 
10381 #if defined (SA_MODE)
10382 /*
10383  * file_tracker_reclaim_marked_deleted () - reclaim all files marked as deleted. this can work only in stand-alone
10384  * mode.
10385  *
10386  * return : error code
10387  * thread_p (in) : thread entry
10388  */
10389 int
10390 file_tracker_reclaim_marked_deleted (THREAD_ENTRY * thread_p)
10391 {
10392  PAGE_PTR page_track_head = NULL;
10393 
10394  PAGE_PTR page_extdata = NULL;
10395  FILE_EXTENSIBLE_DATA *extdata = NULL;
10396  PAGE_PTR page_extdata_next = NULL;
10397  FILE_EXTENSIBLE_DATA *extdata_next = NULL;
10398  FILE_TRACK_ITEM *item = NULL;
10399  VPID vpid_next;
10400  VFID vfid;
10401  int idx_item;
10402  int error_code = NO_ERROR;
10403 
10404  assert (!VPID_ISNULL (&file_Tracker_vpid));
10405  assert (!VFID_ISNULL (&file_Tracker_vfid));
10406 
10407  /* how this works:
10408  * do two steps:
10409  * 1. go through all tracker items and identify heap file entires marked as deleted. deallocate the files and remove
10410  * the items from tracker.
10411  * 2. loop through tracker pages and try to merge two-by-two.
10412  */
10413 
10414  page_track_head = pgbuf_fix (thread_p, &file_Tracker_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
10415  if (page_track_head == NULL)
10416  {
10417  ASSERT_ERROR ();
10418  return error_code;
10419  }
10420 
10421  log_sysop_start (thread_p);
10422 
10423  /* first step: process tracker data, search for files marked deleted, destroy them and remove them from tracker */
10424  page_extdata = page_track_head;
10425 
10426  while (true)
10427  {
10428  extdata = (FILE_EXTENSIBLE_DATA *) page_extdata;
10429  for (idx_item = 0; idx_item < file_extdata_item_count (extdata);)
10430  {
10431  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, idx_item);
10432  if ((FILE_TYPE) item->type == FILE_HEAP && item->metadata.heap.is_marked_deleted)
10433  {
10434  /* destroy file */
10435  vfid.volid = item->volid;
10436  vfid.fileid = item->fileid;
10437  error_code = file_destroy (thread_p, &vfid, false);
10438  if (error_code != NO_ERROR)
10439  {
10440  ASSERT_ERROR ();
10441  goto exit;
10442  }
10443  /* already removed by file_destroy. we don't have to increment idx_item */
10444  }
10445  else
10446  {
10447  /* go to next */
10448  idx_item++;
10449  }
10450  }
10451 
10452  /* go to next extensible data page */
10453  vpid_next = extdata->vpid_next;
10454  if (page_extdata != NULL && page_extdata != page_track_head)
10455  {
10456  pgbuf_unfix_and_init (thread_p, page_extdata);
10457  }
10458  page_extdata = NULL;
10459  if (VPID_ISNULL (&vpid_next))
10460  {
10461  /* no next page */
10462  break;
10463  }
10464  page_extdata = pgbuf_fix (thread_p, &vpid_next, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
10465  if (page_extdata == NULL)
10466  {
10467  ASSERT_ERROR_AND_SET (error_code);
10468  goto exit;
10469  }
10470  /* loop again */
10471  }
10472 
10473  /* try merges */
10474  assert (page_extdata == NULL);
10475  page_extdata = page_track_head;
10476  extdata = (FILE_EXTENSIBLE_DATA *) page_extdata;
10477  while (!VPID_ISNULL (&extdata->vpid_next))
10478  {
10479  page_extdata_next = pgbuf_fix (thread_p, &extdata->vpid_next, OLD_PAGE, PGBUF_LATCH_WRITE,
10481  if (page_extdata_next == NULL)
10482  {
10483  ASSERT_ERROR_AND_SET (error_code);
10484  goto exit;
10485  }
10486  extdata_next = (FILE_EXTENSIBLE_DATA *) page_extdata_next;
10487  if (file_extdata_merge_pages (thread_p, extdata_next, page_extdata_next, extdata, page_extdata,
10488  file_compare_track_items, true))
10489  {
10490  /* merged next into current. deallocate next. */
10491  pgbuf_get_vpid (page_extdata_next, &vpid_next);
10492  pgbuf_unfix_and_init (thread_p, page_extdata_next);
10493 
10494  error_code = file_dealloc (thread_p, &file_Tracker_vfid, &vpid_next, FILE_TRACKER);
10495  if (error_code != NO_ERROR)
10496  {
10497  ASSERT_ERROR ();
10498  goto exit;
10499  }
10500 
10501  /* we can try to merge into this page again. fall through without advancing */
10502  }
10503  else
10504  {
10505  /* advance to next page */
10506  if (page_extdata != page_track_head)
10507  {
10508  pgbuf_unfix (thread_p, page_extdata);
10509  }
10510  page_extdata = page_extdata_next;
10511  extdata = extdata_next;
10512  page_extdata_next = NULL;
10513  }
10514  }
10515 
10516  /* finished successfully */
10517  assert (error_code == NO_ERROR);
10518 
10519 exit:
10520 
10522  if (error_code != NO_ERROR)
10523  {
10524  log_sysop_abort (thread_p);
10525  }
10526  else
10527  {
10528  log_sysop_commit (thread_p);
10529  }
10530  assert (page_extdata_next == NULL || page_extdata_next != page_track_head);
10531  if (page_extdata_next != NULL)
10532  {
10533  pgbuf_unfix (thread_p, page_extdata_next);
10534  }
10535  if (page_extdata != NULL && page_extdata != page_track_head)
10536  {
10537  pgbuf_unfix (thread_p, page_extdata);
10538  }
10539  if (page_track_head != NULL)
10540  {
10541  pgbuf_unfix (thread_p, page_track_head);
10542  }
10543  return error_code;
10544 }
10545 #endif /* SA_MODE */
10546 
10547 /*
10548  * file_tracker_get_and_protect () - get a file from tracker. if we want to get b-tree or heap files, we must first
10549  * protect them by locking class.
10550  *
10551  * return : error code
10552  * thread_p (in) : thread entry
10553  * desired_type (in) : desired file type. FILE_UNKNOWN_TYPE for any type.
10554  * item (in) : tracker item
10555  * class_oid (out) : output locked class OID (for b-tree and heap). NULL OID if no class is locked.
10556  * stop (out) : output true when item is accepted
10557  */
10558 STATIC_INLINE int
10559 file_tracker_get_and_protect (THREAD_ENTRY * thread_p, FILE_TYPE desired_type, FILE_TRACK_ITEM * item, OID * class_oid,
10560  bool * stop)
10561 {
10562  VPID vpid_fhead;
10563  PAGE_PTR page_fhead = NULL;
10564  FILE_HEADER *fhead = NULL;
10565  int error_code = NO_ERROR;
10566 
10567  assert (class_oid != NULL && OID_ISNULL (class_oid));
10568 
10569  /* how it works:
10570  * this is part of the tracker iterate without holding latch on tracker during the entire iteration. however, it can
10571  * only work if the files processed outside latch are protected from being destroyed. otherwise, resuming is
10572  * impossible. most file types are not mutable, so they don't need protection. however, for b-tree and heap files we
10573  * need to read class OID from descriptor and try to lock it (conditionally!). this is a best-effort approach, if the
10574  * locking fails, we just skip the file. */
10575 
10576  /* check file type is right */
10577  switch (desired_type)
10578  {
10579  case FILE_UNKNOWN_TYPE:
10580  /* accept any type */
10581  break;
10582  case FILE_HEAP:
10583  case FILE_HEAP_REUSE_SLOTS:
10584  /* accept heap or heap reuse slots */
10585  if ((FILE_TYPE) item->type != FILE_HEAP && (FILE_TYPE) item->type != FILE_HEAP_REUSE_SLOTS)
10586  {
10587  /* reject */
10588  return NO_ERROR;
10589  }
10590  break;
10591  default:
10592  /* accept the exact file type */
10593  if ((FILE_TYPE) item->type != desired_type)
10594  {
10595  /* reject */
10596  return NO_ERROR;
10597  }
10598  break;
10599  }
10600 
10601  /* now we need to make sure the file is protected. most types are not mutable (cannot be created or destroyed during
10602  * run-time), but b-tree and heap files must be protected by lock. */
10603  switch ((FILE_TYPE) item->type)
10604  {
10605  case FILE_HEAP:
10606  /* these files may be marked for delete. check this is not a deleted file */
10607  if (item->metadata.heap.is_marked_deleted)
10608  {
10609  /* reject */
10610  return NO_ERROR;
10611  }
10612  /* we need to protect with lock. fall through */
10613  break;
10614  case FILE_HEAP_REUSE_SLOTS:
10615  case FILE_BTREE:
10618  /* we need to protect with lock. fall through */
10619  break;
10620  default:
10621  /* immutable file types. no protection required */
10622  *stop = true;
10623  return NO_ERROR;
10624  }
10625 
10626  /* we need to fix file header and read the class oid from descriptor */
10627  vpid_fhead.volid = item->volid;
10628  vpid_fhead.pageid = item->fileid;
10629  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
10630  if (page_fhead == NULL)
10631  {
10632  ASSERT_ERROR_AND_SET (error_code);
10633  return error_code;
10634  }
10635  fhead = (FILE_HEADER *) page_fhead;
10636  file_header_sanity_check (thread_p, fhead);
10637 
10638  /* read class OID */
10639  switch ((FILE_TYPE) item->type)
10640  {
10641  case FILE_BTREE:
10642  *class_oid = fhead->descriptor.btree.class_oid;
10643  break;
10644  case FILE_HEAP:
10645  case FILE_HEAP_REUSE_SLOTS:
10646  *class_oid = fhead->descriptor.heap.class_oid;
10647  break;
10649  *class_oid = fhead->descriptor.heap_overflow.class_oid;
10650  break;
10652  *class_oid = fhead->descriptor.btree_key_overflow.class_oid;
10653  break;
10654  default:
10655  assert (false);
10656  break;
10657  }
10658  pgbuf_unfix (thread_p, page_fhead);
10659 
10660  if (OID_ISNULL (class_oid))
10661  {
10662  /* this must be boot_Db_parm file; cannot be deleted so we don't need lock. */
10663  *stop = true;
10664  return NO_ERROR;
10665  }
10666 
10667  /* try conditional lock */
10668  if (lock_object (thread_p, class_oid, oid_Root_class_oid, FILE_GET_TRACKER_LOCK_MODE (desired_type),
10670  {
10672  OID_AS_ARGS (class_oid));
10673  OID_SET_NULL (class_oid);
10674  }
10675  else
10676  {
10677  /* stop at this file */
10678  *stop = true;
10679  }
10680 
10681  /* finished */
10682  return NO_ERROR;
10683 }
10684 
10685 /*
10686  * file_tracker_interruptable_iterate () - iterate in file tracker and get a new file of desired type
10687  *
10688  * return : error code
10689  * thread_p (in) : thread entry
10690  * desired_ftype (in) : desired type
10691  * vfid (in) : file identifier and iterator cursor. iterate must start with a NULL identifier
10692  * class_oid (in) : locked class OID (used to protect b-tree and heap files)
10693  */
10694 int
10695 file_tracker_interruptable_iterate (THREAD_ENTRY * thread_p, FILE_TYPE desired_ftype, VFID * vfid, OID * class_oid)
10696 {
10697  PAGE_PTR page_track_head = NULL;
10698  PAGE_PTR page_track_other = NULL;
10699  PAGE_PTR page_extdata = NULL;
10700  FILE_EXTENSIBLE_DATA *extdata = NULL;
10701  FILE_TRACK_ITEM *item;
10702  bool found = false;
10703  bool stop = false;
10704  int idx_item;
10705  VPID vpid_next;
10706 #if !defined (NDEBUG)
10707  VFID vfid_prev_cursor = *vfid;
10708 #endif /* !NDEBUG */
10709  int error_code = NO_ERROR;
10710 
10711  assert (vfid != NULL);
10712  assert (class_oid != NULL);
10713 
10714  /* how it works:
10715  * start from given VFID and get a new file of desired type. for b-tree and heap files, we also need to lock their
10716  * class OID in order to protect them from being removed. otherwise we could not resume in next iteration. */
10717 
10718  page_track_head = pgbuf_fix (thread_p, &file_Tracker_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
10719  if (page_track_head == NULL)
10720  {
10721  ASSERT_ERROR_AND_SET (error_code);
10722  return error_code;
10723  }
10724 
10725  if (!OID_ISNULL (class_oid))
10726  {
10727  /* now that we fixed tracker header page, we no longer need lock protection. */
10728  lock_unlock_object (thread_p, class_oid, oid_Root_class_oid, FILE_GET_TRACKER_LOCK_MODE (desired_ftype), true);
10729  OID_SET_NULL (class_oid);
10730  }
10731 
10732  extdata = (FILE_EXTENSIBLE_DATA *) page_track_head;
10733  if (VFID_ISNULL (vfid))
10734  {
10735  /* starting position is first */
10736  idx_item = 0;
10737  page_extdata = page_track_head;
10738  }
10739  else
10740  {
10741  FILE_TRACK_ITEM item_search;
10742  item_search.volid = vfid->volid;
10743  item_search.fileid = vfid->fileid;
10744  error_code =
10745  file_extdata_search_item (thread_p, &extdata, &item_search, file_compare_track_items, true, false, &found,
10746  &idx_item, &page_track_other);
10747  if (error_code != NO_ERROR)
10748  {
10749  ASSERT_ERROR ();
10750  goto exit;
10751  }
10752  if (!found)
10753  {
10754  /* we are in trouble */
10755  assert_release (false);
10756  error_code = ER_FAILED;
10757  goto exit;
10758  }
10759  page_extdata = page_track_other != NULL ? page_track_other : page_track_head;
10760  /* move to next */
10761  idx_item++;
10762  }
10763 
10764  assert (extdata == (FILE_EXTENSIBLE_DATA *) page_extdata);
10765  /* start iterating until stop is issued */
10766  while (true)
10767  {
10768  for (; idx_item < file_extdata_item_count (extdata); idx_item++)
10769  {
10770  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, idx_item);
10771  error_code = file_tracker_get_and_protect (thread_p, desired_ftype, item, class_oid, &stop);
10772  if (error_code != NO_ERROR)
10773  {
10774  ASSERT_ERROR ();
10775  goto exit;
10776  }
10777  if (stop)
10778  {
10779  vfid->volid = item->volid;
10780  vfid->fileid = item->fileid;
10781  goto exit;
10782  }
10783  }
10784  vpid_next = extdata->vpid_next;
10785  if (page_track_other != NULL)
10786  {
10787  pgbuf_unfix_and_init (thread_p, page_track_other);
10788  }
10789  if (VPID_ISNULL (&vpid_next))
10790  {
10791  /* ended */
10792  break;
10793  }
10794  page_track_other = pgbuf_fix (thread_p, &vpid_next, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
10795  if (page_track_other == NULL)
10796  {
10797  ASSERT_ERROR_AND_SET (error_code);
10798  goto exit;
10799  }
10800  page_extdata = page_track_other;
10801  extdata = (FILE_EXTENSIBLE_DATA *) page_extdata;
10802  idx_item = 0;
10803  }
10804 
10805  /* end of tracker */
10806  VFID_SET_NULL (vfid);
10807  assert (OID_ISNULL (class_oid));
10808  assert (error_code == NO_ERROR);
10809 
10810 exit:
10811  if (page_track_other != NULL)
10812  {
10813  pgbuf_unfix (thread_p, page_track_other);
10814  }
10815  if (page_track_head != NULL)
10816  {
10817  pgbuf_unfix (thread_p, page_track_head);
10818  }
10819 
10820  /* check cursor is not repeated (unless there is an error) */
10821  assert (error_code != NO_ERROR || VFID_ISNULL (&vfid_prev_cursor) || !VFID_EQ (&vfid_prev_cursor, vfid));
10822 
10823  return error_code;
10824 }
10825 
10826 /*
10827  * file_tracker_item_dump () - FILE_TRACK_ITEM_FUNC to dump file
10828  *
10829  * return : error code
10830  * thread_p (in) : thread entry
10831  * page_of_item (in) : tracker page
10832  * extdata (in) : tracker extensible data
10833  * index_item (in) : item index
10834  * stop (in) : not used
10835  * args (in) : FILE *
10836  */
10837 static int
10838 file_tracker_item_dump (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA * extdata, int index_item,
10839  bool * stop, void *args)
10840 {
10841  VFID vfid;
10842  FILE_TRACK_ITEM *item;
10843  FILE *fp = (FILE *) args;
10844  int error_code = NO_ERROR;
10845 
10846  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
10847  vfid.volid = item->volid;
10848  vfid.fileid = item->fileid;
10849 
10850  error_code = file_dump (thread_p, &vfid, fp);
10851  if (error_code != NO_ERROR)
10852  {
10853  ASSERT_ERROR ();
10854  return error_code;
10855  }
10856 
10857  return NO_ERROR;
10858 }
10859 
10860 /*
10861  * file_tracker_dump () - dump all files in file tracker
10862  *
10863  * return : error code
10864  * thread_p (in) : thread entry
10865  * fp (in) : output file
10866  */
10867 int
10868 file_tracker_dump (THREAD_ENTRY * thread_p, FILE * fp)
10869 {
10870  fprintf (fp, "\n\n DUMPING TRACKED FILES \n");
10872 }
10873 
10874 /*
10875  * file_tracker_item_dump_capacity () - FILE_TRACK_ITEM_FUNC to dump file capacity
10876  *
10877  * return : error code
10878  * thread_p (in) : thread entry
10879  * page_of_item (in) : tracker page
10880  * extdata (in) : tracker extensible data
10881  * index_item (in) : item index
10882  * stop (in) : not used
10883  * args (in) : FILE *
10884  */
10885 static int
10887  int index_item, bool * stop, void *args)
10888 {
10889  FILE_TRACK_ITEM *item;
10890  VPID vpid_fhead;
10891  PAGE_PTR page_fhead = NULL;
10892  FILE_HEADER *fhead = NULL;
10893  FILE *fp = (FILE *) args;
10894  int error_code = NO_ERROR;
10895 
10896  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
10897 
10898  vpid_fhead.volid = item->volid;
10899  vpid_fhead.pageid = item->fileid;
10900  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
10901  if (page_fhead == NULL)
10902  {
10903  ASSERT_ERROR_AND_SET (error_code);
10904  return error_code;
10905  }
10906  fhead = (FILE_HEADER *) page_fhead;
10907  file_header_sanity_check (thread_p, fhead);
10908 
10909  fprintf (fp, "%4d|%4d %5d %-22s ", item->volid, item->fileid, fhead->n_page_user, file_type_to_string (fhead->type));
10910  if ((FILE_TYPE) item->type == FILE_HEAP && item->metadata.heap.is_marked_deleted)
10911  {
10912  fprintf (fp, "Marked as deleted... ");
10913  }
10914 
10915  file_header_dump_descriptor (thread_p, fhead, fp);
10916 
10917  pgbuf_unfix (thread_p, page_fhead);
10918  return NO_ERROR;
10919 }
10920 
10921 /*
10922  * file_tracker_dump_all_capacities () - dump capacities for all files
10923  *
10924  * return : error code
10925  * thread_p (in) : thread entry
10926  * fp (in) : output file
10927  */
10928 int
10930 {
10931  int error_code = NO_ERROR;
10932 
10933  fprintf (fp, " VFID npages type FDES\n");
10935  if (error_code != NO_ERROR)
10936  {
10937  ASSERT_ERROR ();
10938  return error_code;
10939  }
10940 
10941  return NO_ERROR;
10942 }
10943 
10944 /*
10945  * file_tracker_item_dump_heap () - FILE_TRACK_ITEM_FUNC to dump heap file
10946  *
10947  * return : error code
10948  * thread_p (in) : thread entry
10949  * page_of_item (in) : tracker page
10950  * extdata (in) : tracker extensible data
10951  * index_item (in) : item index
10952  * stop (in) : not used
10953  * args (in) : context
10954  */
10955 static int
10957  int index_item, bool * stop, void *args)
10958 {
10959  FILE_TRACK_ITEM *item;
10960  HFID hfid;
10962  int error_code = NO_ERROR;
10963 
10964  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
10965  if ((FILE_TYPE) item->type != FILE_HEAP && (FILE_TYPE) item->type != FILE_HEAP_REUSE_SLOTS)
10966  {
10967  return NO_ERROR;
10968  }
10969 
10970  hfid.vfid.volid = item->volid;
10971  hfid.vfid.fileid = item->fileid;
10972 
10973  error_code = heap_get_hfid_from_vfid (thread_p, &hfid.vfid, &hfid);
10974  if (error_code != NO_ERROR)
10975  {
10976  ASSERT_ERROR ();
10977  return error_code;
10978  }
10979 
10980  heap_dump (thread_p, context->fp, &hfid, context->dump_records);
10981 
10982  return NO_ERROR;
10983 }
10984 
10985 /*
10986  * file_tracker_dump_all_heap () - dump all heap files
10987  *
10988  * return : error code
10989  * thread_p (in) : thread entry
10990  * fp (in) : output file
10991  * dump_records (in) : true to dump records
10992  */
10993 int
10994 file_tracker_dump_all_heap (THREAD_ENTRY * thread_p, FILE * fp, bool dump_records)
10995 {
10997 
10998  context.fp = fp;
10999  context.dump_records = dump_records;
11000 
11001  return file_tracker_map (thread_p, PGBUF_LATCH_READ, file_tracker_item_dump_heap, &context);
11002 }
11003 
11004 /*
11005  * file_tracker_item_dump_heap_capacity () - FILE_TRACK_ITEM_FUNC to dump heap file capacity
11006  *
11007  * return : error code
11008  * thread_p (in) : thread entry
11009  * page_of_item (in) : tracker page
11010  * extdata (in) : tracker extensible data
11011  * index_item (in) : item index
11012  * stop (in) : not used
11013  * args (in) : context
11014  */
11015 static int
11017  int index_item, bool * stop, void *args)
11018 {
11019  FILE_TRACK_ITEM *item;
11020  HFID hfid;
11021  FILE *fp = (FILE *) args;
11022  int error_code = NO_ERROR;
11023 
11024  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
11025  if ((FILE_TYPE) item->type != FILE_HEAP && (FILE_TYPE) item->type != FILE_HEAP_REUSE_SLOTS)
11026  {
11027  return NO_ERROR;
11028  }
11029 
11030  hfid.vfid.volid = item->volid;
11031  hfid.vfid.fileid = item->fileid;
11032 
11033  error_code = heap_get_hfid_from_vfid (thread_p, &hfid.vfid, &hfid);
11034  if (error_code != NO_ERROR)
11035  {
11036  ASSERT_ERROR ();
11037  return error_code;
11038  }
11039 
11040  error_code = heap_dump_capacity (thread_p, fp, &hfid);
11041  if (error_code != NO_ERROR)
11042  {
11043  ASSERT_ERROR ();
11044  return error_code;
11045  }
11046 
11047  return NO_ERROR;
11048 }
11049 
11050 /*
11051  * file_tracker_dump_all_heap_capacities () - dump all heap capacities
11052  *
11053  * return : error code
11054  * thread_p (in) : thread entry
11055  * fp (in) : output file
11056  */
11057 int
11059 {
11060  fprintf (fp, "IO_PAGESIZE = %d, DB_PAGESIZE = %d, Recv_overhead = %d\n", IO_PAGESIZE, DB_PAGESIZE,
11063 }
11064 
11065 /*
11066  * file_tracker_item_dump_btree_capacity () - FILE_TRACK_ITEM_FUNC to dump b-tree file capacity
11067  *
11068  * return : error code
11069  * thread_p (in) : thread entry
11070  * page_of_item (in) : tracker page
11071  * extdata (in) : tracker extensible data
11072  * index_item (in) : item index
11073  * stop (in) : not used
11074  * args (in) : context
11075  */
11076 static int
11078  int index_item, bool * stop, void *args)
11079 {
11080  FILE_TRACK_ITEM *item;
11081  BTID btid;
11082  FILE *fp = (FILE *) args;
11083  int error_code = NO_ERROR;
11084 
11085  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
11086  if ((FILE_TYPE) item->type != FILE_BTREE)
11087  {
11088  return NO_ERROR;
11089  }
11090 
11091  /* get btid */
11092  btid.vfid.volid = item->volid;
11093  btid.vfid.fileid = item->fileid;
11094 
11095  error_code = btree_get_btid_from_file (thread_p, &btid.vfid, &btid);
11096  if (error_code != NO_ERROR)
11097  {
11098  ASSERT_ERROR ();
11099  return error_code;
11100  }
11101 
11102  /* dump */
11103  error_code = btree_dump_capacity (thread_p, fp, &btid);
11104  if (error_code != NO_ERROR)
11105  {
11106  ASSERT_ERROR ();
11107  return error_code;
11108  }
11109 
11110  return NO_ERROR;
11111 }
11112 
11113 /*
11114  * file_tracker_dump_all_btree_capacities () - dump all b-tree capacities
11115  *
11116  * return : error code
11117  * thread_p (in) : thread entry
11118  * fp (in) : output file
11119  */
11120 int
11122 {
11124 }
11125 
11126 /*
11127  * file_tracker_check () - check all files have valid tables. stand-alone mode will also cross check with disk sector
11128  * table maps.
11129  *
11130  * return : error code
11131  * thread_p (in) : thread entry
11132  */
11135 {
11136  DISK_ISVALID allvalid = DISK_VALID;
11137  DISK_ISVALID valid = DISK_VALID;
11138  int error_code = NO_ERROR;
11139 
11140 #if defined (SERVER_MODE)
11141  VFID vfid = VFID_INITIALIZER;
11142  OID class_oid = OID_INITIALIZER;
11143 
11144  valid = file_table_check (thread_p, &file_Tracker_vfid, NULL);
11145  if (valid == DISK_ERROR)
11146  {
11147  ASSERT_ERROR ();
11148  return DISK_ERROR;
11149  }
11150  else if (valid == DISK_INVALID)
11151  {
11152  assert_release (false);
11153  allvalid = DISK_INVALID;
11154  }
11155 
11156  while (true)
11157  {
11158  error_code = file_tracker_interruptable_iterate (thread_p, FILE_UNKNOWN_TYPE, &vfid, &class_oid);
11159  if (error_code != NO_ERROR)
11160  {
11161  ASSERT_ERROR ();
11162  allvalid = (allvalid == DISK_VALID) ? DISK_ERROR : allvalid;
11163  break;
11164  }
11165  if (VFID_ISNULL (&vfid))
11166  {
11167  /* all files processed */
11168  break;
11169  }
11170  valid = file_table_check (thread_p, &vfid, NULL);
11171  if (valid == DISK_INVALID)
11172  {
11173  assert (false);
11174  allvalid = DISK_INVALID;
11175  }
11176  else if (valid == DISK_ERROR)
11177  {
11178  ASSERT_ERROR ();
11179  allvalid = (allvalid == DISK_VALID) ? DISK_ERROR : allvalid;
11180  break;
11181  }
11182  }
11183 
11184  if (!OID_ISNULL (&class_oid))
11185  {
11186  lock_unlock_object (thread_p, &class_oid, oid_Root_class_oid, SCH_S_LOCK, true);
11187  }
11188 #else /* !SERVER_MODE */ /* SA_MODE */
11189  DISK_VOLMAP_CLONE *disk_map_clone = NULL;
11190 
11191  error_code = disk_map_clone_create (thread_p, &disk_map_clone);
11192  if (error_code != NO_ERROR)
11193  {
11194  ASSERT_ERROR ();
11195  return DISK_ERROR;
11196  }
11197 
11198  valid = file_table_check (thread_p, &file_Tracker_vfid, disk_map_clone);
11199  if (valid == DISK_INVALID)
11200  {
11201  assert_release (false);
11202  allvalid = DISK_INVALID;
11203  /* continue checks */
11204  }
11205  else if (valid == DISK_ERROR)
11206  {
11207  ASSERT_ERROR ();
11208  return DISK_ERROR;
11209  }
11210 
11211  error_code = file_tracker_map (thread_p, PGBUF_LATCH_READ, file_tracker_item_check, disk_map_clone);
11212  if (error_code == ER_FAILED)
11213  {
11214  assert_release (false);
11215  disk_map_clone_free (&disk_map_clone);
11216  allvalid = DISK_INVALID;
11217  }
11218  else if (error_code != NO_ERROR)
11219  {
11220  ASSERT_ERROR ();
11221  disk_map_clone_free (&disk_map_clone);
11222  return allvalid == DISK_VALID ? DISK_ERROR : allvalid;
11223  }
11224  else
11225  {
11226  /* check all sectors have been cleared */
11227  valid = disk_map_clone_check_leaks (disk_map_clone);
11228  if (valid == DISK_INVALID)
11229  {
11230  assert_release (false);
11231  allvalid = DISK_INVALID;
11232  }
11233  else if (valid == DISK_ERROR)
11234  {
11235  ASSERT_ERROR ();
11236  allvalid = allvalid == DISK_VALID ? DISK_ERROR : allvalid;
11237  }
11238  disk_map_clone_free (&disk_map_clone);
11239  }
11240 
11241 #endif /* SA_MODE */
11242 
11243  return allvalid;
11244 }
11245 
11246 #if defined (SA_MODE)
11247 /*
11248  * file_tracker_item_check () - check file table and cross-check sector usage with disk sector table maps
11249  *
11250  * return : error code (ER_FAILED for invalid state)
11251  * thread_p (in) : thread entry
11252  * page_of_item (in) : tracker page
11253  * extdata (in) : tracker extensible data
11254  * index_item (in) : item index
11255  * stop (in) : not used
11256  * args (in/out) : DISK_VOLMAP_CLONE *
11257  */
11258 static int
11259 file_tracker_item_check (THREAD_ENTRY * thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA * extdata, int index_item,
11260  bool * stop, void *args)
11261 {
11262  DISK_VOLMAP_CLONE *disk_map_clone = (DISK_VOLMAP_CLONE *) args;
11263  FILE_TRACK_ITEM *item;
11264  VFID vfid;
11265  DISK_ISVALID valid = DISK_VALID;
11266  int error_code = NO_ERROR;
11267 
11268  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
11269  vfid.volid = item->volid;
11270  vfid.fileid = item->fileid;
11271 
11272  valid = file_table_check (thread_p, &vfid, disk_map_clone);
11273  if (valid == DISK_INVALID)
11274  {
11275  assert_release (false);
11276  return ER_FAILED;
11277  }
11278  else if (valid == DISK_ERROR)
11279  {
11280  ASSERT_ERROR_AND_SET (error_code);
11281  return error_code;
11282  }
11283 
11284  return NO_ERROR;
11285 }
11286 #endif /* SA_MODE */
11287 
11288 /*
11289  * file_tracker_item_spacedb () - FILE_TRACKER_ITEM_FUNC to collect space information
11290  *
11291  * return : error code
11292  * thread_p (in) : thread entry
11293  * page_of_item (in) : page of item
11294  * extdata (in) : extensible data
11295  * index_item (in) : index of item
11296  * stop (in) : ignored
11297  * args (in/out) : SPACEDB_FILES *
11298  */
11299 static int
11301  int index_item, bool * stop, void *args)
11302 {
11303  FILE_TRACK_ITEM *item;
11304  VPID vpid_fhead;
11305  PAGE_PTR page_fhead = NULL;
11306  FILE_HEADER *fhead = NULL;
11307  SPACEDB_FILES *spacedb = (SPACEDB_FILES *) args;
11308  SPACEDB_FILE_TYPE spacedb_ftype;
11309  int error_code = NO_ERROR;
11310 
11311  item = (FILE_TRACK_ITEM *) file_extdata_at (extdata, index_item);
11312  vpid_fhead.volid = item->volid;
11313  vpid_fhead.pageid = item->fileid;
11314 
11315  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
11316  if (page_fhead == NULL)
11317  {
11318  ASSERT_ERROR_AND_SET (error_code);
11319  return error_code;
11320  }
11321  fhead = (FILE_HEADER *) page_fhead;
11322 
11323  switch (fhead->type)
11324  {
11325  case FILE_BTREE:
11326  /* index file */
11327  spacedb_ftype = SPACEDB_INDEX_FILE;
11328  break;
11329  case FILE_HEAP:
11330  case FILE_HEAP_REUSE_SLOTS:
11331  /* heap file */
11332  spacedb_ftype = SPACEDB_HEAP_FILE;
11333  break;
11334  default:
11335  /* system file */
11336  spacedb_ftype = SPACEDB_SYSTEM_FILE;
11337  break;
11338  }
11339  spacedb[spacedb_ftype].nfile++;
11340  spacedb[spacedb_ftype].npage_ftab += fhead->n_page_ftab;
11341  spacedb[spacedb_ftype].npage_user += fhead->n_page_user;
11342  spacedb[spacedb_ftype].npage_reserved += fhead->n_page_free;
11343 
11344  pgbuf_unfix_and_init (thread_p, page_fhead);
11345  return NO_ERROR;
11346 }
11347 
11348 /*
11349  * file_tracker_spacedb () - collect space usage information from all files
11350  *
11351  * return : error code
11352  * thread_p (in) : thread entry
11353  * spacedb (out) : output space usage information
11354  */
11355 static int
11357 {
11358  VPID vpid_fhead;
11359  PAGE_PTR page_fhead;
11360  FILE_HEADER *fhead;
11361 
11362  int error_code = NO_ERROR;
11363 
11364  error_code = file_tracker_map (thread_p, PGBUF_LATCH_READ, file_tracker_item_spacedb, spacedb);
11365  if (error_code != NO_ERROR)
11366  {
11367  ASSERT_ERROR ();
11368  return error_code;
11369  }
11370 
11371  /* file tracker is also a system file */
11372  FILE_GET_HEADER_VPID (&file_Tracker_vfid, &vpid_fhead);
11373  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
11374  if (page_fhead == NULL)
11375  {
11376  ASSERT_ERROR_AND_SET (error_code);
11377  return error_code;
11378  }
11379  fhead = (FILE_HEADER *) page_fhead;
11380 
11381  spacedb[SPACEDB_SYSTEM_FILE].nfile++;
11382  spacedb[SPACEDB_SYSTEM_FILE].npage_ftab += fhead->n_page_ftab;
11383  spacedb[SPACEDB_SYSTEM_FILE].npage_user += fhead->n_page_user;
11384  spacedb[SPACEDB_SYSTEM_FILE].npage_reserved += fhead->n_page_free;
11385 
11386  pgbuf_unfix_and_init (thread_p, page_fhead);
11387  return NO_ERROR;
11388 }
11389 
11390 /************************************************************************/
11391 /* File descriptor section */
11392 /************************************************************************/
11393 
11394 /*
11395  * file_descriptor_get () - get file descriptor from header
11396  *
11397  * return : error code
11398  * thread_p (in) : thread entry
11399  * vfid (in) : file identifier
11400  * desc_out (in) : output file descriptor
11401  */
11402 int
11403 file_descriptor_get (THREAD_ENTRY * thread_p, const VFID * vfid, FILE_DESCRIPTORS * desc_out)
11404 {
11405  VPID vpid_fhead;
11406  PAGE_PTR page_fhead = NULL;
11407  FILE_HEADER *fhead;
11408  int error_code = NO_ERROR;
11409 
11410  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
11411  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
11412  if (page_fhead == NULL)
11413  {
11414  ASSERT_ERROR_AND_SET (error_code);
11415  return error_code;
11416  }
11417  fhead = (FILE_HEADER *) page_fhead;
11418  file_header_sanity_check (thread_p, fhead);
11419 
11420  *desc_out = fhead->descriptor;
11421 
11422  pgbuf_unfix (thread_p, page_fhead);
11423  return NO_ERROR;
11424 }
11425 
11426 /*
11427  * file_descriptor_update () - Update file descriptor
11428  *
11429  * return : error code
11430  * thread_p (in) : thread entry
11431  * vfid (in) : file identifier
11432  * des_new (in) : new file descriptor
11433  */
11434 int
11435 file_descriptor_update (THREAD_ENTRY * thread_p, const VFID * vfid, void *des_new)
11436 {
11437  VPID vpid_fhead;
11438  PAGE_PTR page_fhead = NULL;
11439  FILE_HEADER *fhead = NULL;
11440  int error_code = NO_ERROR;
11441 
11442  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
11443  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
11444  if (page_fhead == NULL)
11445  {
11446  ASSERT_ERROR_AND_SET (error_code);
11447  return error_code;
11448  }
11449  fhead = (FILE_HEADER *) page_fhead;
11450  file_header_sanity_check (thread_p, fhead);
11451 
11452  log_append_undoredo_data2 (thread_p, RVFL_FILEDESC_UPD, NULL, page_fhead,
11453  (PGLENGTH) ((char *) &fhead->descriptor - page_fhead), sizeof (fhead->descriptor),
11454  sizeof (fhead->descriptor), &fhead->descriptor, des_new);
11455 
11456  memcpy (&fhead->descriptor, des_new, sizeof (fhead->descriptor));
11457 
11458  pgbuf_set_dirty (thread_p, page_fhead, FREE);
11459  return NO_ERROR;
11460 }
11461 
11462 /*
11463  * file_descriptor_dump () - dump file descriptor
11464  *
11465  * return : error code
11466  * thread_p (in) : thread entry
11467  * vfid (in) : file identifier
11468  * fp (in) : output file
11469  */
11470 int
11471 file_descriptor_dump (THREAD_ENTRY * thread_p, const VFID * vfid, FILE * fp)
11472 {
11473  VPID vpid_fhead;
11474  PAGE_PTR page_fhead = NULL;
11475  FILE_HEADER *fhead = NULL;
11476  int error_code = NO_ERROR;
11477 
11478  FILE_GET_HEADER_VPID (vfid, &vpid_fhead);
11479  page_fhead = pgbuf_fix (thread_p, &vpid_fhead, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
11480  if (page_fhead == NULL)
11481  {
11482  ASSERT_ERROR_AND_SET (error_code);
11483  return error_code;
11484  }
11485  fhead = (FILE_HEADER *) page_fhead;
11486  file_header_sanity_check (thread_p, fhead);
11487 
11488  file_header_dump_descriptor (thread_p, fhead, fp);
11489 
11490  pgbuf_unfix (thread_p, page_fhead);
11491  return NO_ERROR;
11492 }
11493 
11494 
11495 /*
11496  * xfile_apply_tde_to_class_files () - set TDE information to all permanent files related with class_oid
11497  *
11498  * return : error code
11499  * thread_p (in) : thread entry
11500  * oid (in) : class oid
11501  */
11502 int
11503 xfile_apply_tde_to_class_files (THREAD_ENTRY * thread_p, const OID * class_oid)
11504 {
11505  OR_CLASSREP *or_repr = NULL;
11506  TDE_ALGORITHM tde_algo = TDE_ALGORITHM_NONE;
11507  TDE_ALGORITHM prev_tde_algo = TDE_ALGORITHM_NONE;
11509  VFID hovf_vfid;
11510  int idx_in_cache = -1;
11511  int error_code = NO_ERROR;
11512  int i = 0;
11513 
11514  assert (class_oid != NULL);
11515  assert (!OID_ISNULL (class_oid));
11516 
11517  error_code = heap_get_class_tde_algorithm (thread_p, class_oid, &tde_algo);
11518  if (error_code != NO_ERROR)
11519  {
11520  goto exit;
11521  }
11522 
11523  /* It is expected for flags in the class record to be set in advance */
11524  assert (tde_algo != TDE_ALGORITHM_NONE);
11525 
11526  /* apply to heap file and heap overflow file */
11527  error_code = heap_get_class_info (thread_p, class_oid, &hfid, NULL, NULL);
11528  if (error_code != NO_ERROR)
11529  {
11530  goto exit;
11531  }
11532 
11533  error_code = file_apply_tde_algorithm (thread_p, &hfid.vfid, tde_algo);
11534  if (error_code != NO_ERROR)
11535  {
11536  goto exit;
11537  }
11538 
11539  if (heap_ovf_find_vfid (thread_p, &hfid, &hovf_vfid, false, PGBUF_UNCONDITIONAL_LATCH) != NULL)
11540  {
11541  /* not exist */
11542  error_code = file_apply_tde_algorithm (thread_p, &hovf_vfid, tde_algo);
11543  if (error_code != NO_ERROR)
11544  {
11545  goto exit;
11546  }
11547  }
11548 
11549  or_repr = heap_classrepr_get (thread_p, class_oid, NULL, NULL_REPRID, &idx_in_cache);
11550  if (or_repr == NULL)
11551  {
11552  error_code = ER_FAILED;
11553  goto exit;
11554  }
11555 
11556  /* apply to btree files and btree overflow files */
11557  for (i = 0; i < or_repr->n_indexes; i++)
11558  {
11559  VFID bovf_vfid;
11560  BTID btid;
11561  PAGE_PTR root_page = NULL;
11562  VPID root_vpid;
11563  BTREE_ROOT_HEADER *root_header = NULL;
11564 
11565  btid = or_repr->indexes[i].btid;
11566 
11567  root_vpid.volid = btid.vfid.volid; /* read the root page */
11568  root_vpid.pageid = btid.root_pageid;
11569  root_page = pgbuf_fix (thread_p, &root_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
11570  if (root_page == NULL)
11571  {
11572  ASSERT_ERROR_AND_SET (error_code);
11573  goto exit;
11574  }
11575 
11576  (void) pgbuf_check_page_ptype (thread_p, root_page, PAGE_BTREE);
11577 
11578  root_header = btree_get_root_header (thread_p, root_page);
11579  if (root_header == NULL)
11580  {
11581  pgbuf_unfix_and_init (thread_p, root_page);
11582  ASSERT_ERROR_AND_SET (error_code);
11583  goto exit;
11584  }
11585  bovf_vfid = root_header->ovfid;
11586 
11587  pgbuf_unfix_and_init (thread_p, root_page);
11588 
11589  error_code = file_apply_tde_algorithm (thread_p, &btid.vfid, tde_algo);
11590  if (error_code != NO_ERROR)
11591  {
11592  goto exit;
11593  }
11594 
11595  if (!VFID_ISNULL (&bovf_vfid))
11596  {
11597  error_code = file_apply_tde_algorithm (thread_p, &bovf_vfid, tde_algo);
11598  if (error_code != NO_ERROR)
11599  {
11600  goto exit;
11601  }
11602  }
11603  }
11604 
11605 exit:
11606  if (or_repr != NULL)
11607  {
11608  heap_classrepr_free_and_init (or_repr, &idx_in_cache);
11609  }
11610 
11611  return error_code;
11612 }
11613 
11614 /************************************************************************/
11615 /* End of file */
11616 /************************************************************************/
int(* compare_func)(const void *, const void *)
Definition: file_manager.c:241
static int file_numerable_add_page(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, const VPID *vpid)
PGLENGTH offset
Definition: recovery.h:201
int file_destroy(THREAD_ENTRY *thread_p, const VFID *vfid, bool is_temp)
int disk_reserve_sectors(THREAD_ENTRY *thread_p, DB_VOLPURPOSE purpose, VOLID volid_hint, int n_sectors, VSID *reserved_sectors)
char * PAGE_PTR
static int file_full_table_extdata_dump(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, bool *stop, void *args)
#define OID_INITIALIZER
Definition: oid.h:36
static int file_extdata_find_and_remove_item(THREAD_ENTRY *thread_p, FILE_EXTENSIBLE_DATA *extdata_first, PAGE_PTR page_first, const void *item, int(*compare_func)(const void *, const void *), bool ordered, void *item_pop, VPID *vpid_merged)
#define FILE_HEAD_ALLOC_MSG
Definition: file_manager.c:330
#define PGBUF_PAGE_VPID_AS_ARGS(pg)
Definition: page_buffer.h:53
VFID vfid
Definition: file_manager.c:470
int file_temp_retire(THREAD_ENTRY *thread_p, const VFID *vfid)
OID * oid_Root_class_oid
Definition: oid.c:73
int(* FILE_EXTDATA_ITEM_FUNC)(THREAD_ENTRY *thread_p, const void *data, int index, bool *stop, void *args)
Definition: file_manager.c:249
STATIC_INLINE int file_table_dump(THREAD_ENTRY *thread_p, const FILE_HEADER *fhead, FILE *fp) __attribute__((ALWAYS_INLINE))
int file_numerable_find_nth(THREAD_ENTRY *thread_p, const VFID *vfid, int nth, bool auto_alloc, FILE_INIT_PAGE_FUNC f_init, void *f_init_args, VPID *vpid_nth)
int file_rv_partsect_clear(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
static int file_extdata_search_item(THREAD_ENTRY *thread_p, FILE_EXTENSIBLE_DATA **extdata, const void *item_to_find, int(*compare_func)(const void *, const void *), bool is_ordered, bool for_write, bool *found, int *position, PAGE_PTR *page_extdata)
#define NO_ERROR
Definition: error_code.h:46
VPID vpid_find_nth_last
Definition: file_manager.c:150
int file_create(THREAD_ENTRY *thread_p, FILE_TYPE file_type, FILE_TABLESPACE *tablespace, FILE_DESCRIPTORS *des, bool is_temp, bool is_numerable, VFID *vfid)
int file_rv_fhead_sticky_page(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
#define FILE_RV_DEALLOC_RUN_POSTPONE
Definition: file_manager.c:407
void log_append_redo_data(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int length, const void *data)
Definition: log_manager.c:1979
static int file_table_add_full_sector(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, const VSID *vsid)
STATIC_INLINE bool file_partsect_is_full(FILE_PARTIAL_SECTOR *partsect) __attribute__((ALWAYS_INLINE))
#define __attribute__(X)
Definition: porting.h:36
#define VFID_EQ(vfid_ptr1, vfid_ptr2)
Definition: file_manager.h:75
VPID vpid_last_user_page_ftab
Definition: file_manager.c:133
void er_stack_push(void)
static int file_tracker_unregister(THREAD_ENTRY *thread_p, const VFID *vfid)
#define FILE_USER_PAGE_IS_MARKED_DELETED(vpid)
Definition: file_manager.c:446
#define BTID_AS_ARGS(btid)
void log_append_undoredo_data2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, int undo_length, int redo_length, const void *undo_data, const void *redo_data)
Definition: log_manager.c:1861
VPID vpid_sticky_first
Definition: file_manager.c:117
STATIC_INLINE void * file_extdata_end(const FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
#define FILE_TEMPCACHE_ENTRY_AS_ARGS(ent)
Definition: file_manager.c:387
int file_init_temp_page_type(THREAD_ENTRY *thread_p, PAGE_PTR page, void *args)
#define DB_ALIGN_BELOW(offset, align)
Definition: memory_alloc.h:87
STATIC_INLINE void file_log_extdata_set_next(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, PAGE_PTR page, const VPID *vpid_next) __attribute__((ALWAYS_INLINE))
int file_spacedb(THREAD_ENTRY *thread_p, SPACEDB_FILES *spacedb)
#define IO_PAGESIZE
STATIC_INLINE void file_tempcache_push_tran_file(THREAD_ENTRY *thread_p, FILE_TEMPCACHE_ENTRY *entry)
INT32 reserved3
Definition: file_manager.c:157
int file_rv_extdata_add(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
void log_append_undoredo_crumbs(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int num_undo_crumbs, int num_redo_crumbs, const LOG_CRUMB *undo_crumbs, const LOG_CRUMB *redo_crumbs)
Definition: log_manager.c:2030
STATIC_INLINE int file_tracker_get_and_protect(THREAD_ENTRY *thread_p, FILE_TYPE desired_type, FILE_TRACK_ITEM *item, OID *class_oid, bool *stop)
#define ASSERT_ERROR()
void pgbuf_log_new_page(THREAD_ENTRY *thread_p, PAGE_PTR page_new, int data_size, PAGE_TYPE ptype_new)
FILE_BTREE_DES btree
Definition: file_manager.h:134
int file_descriptor_update(THREAD_ENTRY *thread_p, const VFID *vfid, void *des_new)
#define FILE_PERM_TEMP_STRING(is_temp)
Definition: file_manager.c:321
#define HFID_INITIALIZER
int file_dealloc(THREAD_ENTRY *thread_p, const VFID *vfid, const VPID *vpid, FILE_TYPE file_type_hint)
void pgbuf_dealloc_page(THREAD_ENTRY *thread_p, PAGE_PTR page_dealloc)
int file_rv_fhead_dealloc(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
#define pthread_mutex_init(a, b)
Definition: area_alloc.c:48
int bit64_count_trailing_ones(UINT64 i)
Definition: bit.c:513
#define LOG_DATA_ADDR_INITIALIZER
Definition: log_append.hpp:63
void log_sysop_end_logical_compensate(THREAD_ENTRY *thread_p, LOG_LSA *undo_nxlsa)
Definition: log_manager.c:3963
#define LOG_DATA_SIZE
#define SECTOR_FIRST_PAGEID(sid)
PAGEID DKNPAGES
#define VPID_COPY(dest_ptr, src_ptr)
Definition: dbtype_def.h:909
STATIC_INLINE INT16 file_extdata_remaining_capacity(const FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
static int file_temp_reset_user_pages(THREAD_ENTRY *thread_p, const VFID *vfid)
STATIC_INLINE int file_get_tempcache_entry_index(THREAD_ENTRY *thread_p)
int logtb_get_number_of_total_tran_indices(void)
int file_alloc_multiple(THREAD_ENTRY *thread_p, const VFID *vfid, FILE_INIT_PAGE_FUNC f_init, void *f_init_args, int npages, VPID *vpids_out)
#define FILE_PARTSECT_MSG(name)
Definition: file_manager.c:370
int file_numerable_truncate(THREAD_ENTRY *thread_p, const VFID *vfid, DKNPAGES npages)
void log_sysop_start_atomic(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3644
int file_rv_extdata_merge(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
int file_tracker_load(THREAD_ENTRY *thread_p, const VFID *vfid)
#define FILE_HEADER_GET_FULL_FTAB(fh, fulltab)
Definition: file_manager.c:196
#define ER_FAILED
Definition: error_code.h:47
void log_rv_dump_hexa(FILE *fp, int length, void *data)
Definition: log_manager.c:8734
BTREE_ROOT_HEADER * btree_get_root_header(THREAD_ENTRY *thread_p, PAGE_PTR page_ptr)
Definition: btree_load.c:309
INT32 file_flags
Definition: file_manager.c:109
STATIC_INLINE void file_header_dump_descriptor(THREAD_ENTRY *thread_p, const FILE_HEADER *fhead, FILE *fp) __attribute__((ALWAYS_INLINE))
STATIC_INLINE void file_log_extdata_add(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, PAGE_PTR page, int position, int count, const void *data) __attribute__((ALWAYS_INLINE))
int file_get_type(THREAD_ENTRY *thread_p, const VFID *vfid, FILE_TYPE *ftype_out)
#define ALWAYS_INLINE
int file_tracker_reuse_heap(THREAD_ENTRY *thread_p, const OID *class_oid, HFID *hfid_out)
FILE_TRACK_METADATA metadata
Definition: file_manager.c:530
DISK_ISVALID file_check_vpid(THREAD_ENTRY *thread_p, const VFID *vfid, const VPID *vpid_lookup)
#define pthread_mutex_unlock(a)
Definition: area_alloc.c:51
STATIC_INLINE bool file_extdata_is_full(const FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
FILE_TYPE
Definition: file_manager.h:38
int file_rv_fhead_convert_user_to_ftab_page(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
#define pgbuf_unfix(thread_p, pgptr)
Definition: page_buffer.h:276
STATIC_INLINE void file_tempcache_lock(void)
Definition: file_manager.c:778
int file_create_temp_numerable(THREAD_ENTRY *thread_p, int npages, VFID *vfid)
#define FILE_IS_NUMERABLE(fh)
Definition: file_manager.c:171
#define SECTOR_LAST_PAGEID(sid)
int file_manager_init(void)
static int file_tempcache_init(void)
int n_sector_total
Definition: file_manager.c:101
#define ASSERT_ERROR_AND_SET(error_code)
static int file_extdata_apply_funcs(THREAD_ENTRY *thread_p, FILE_EXTENSIBLE_DATA *extdata_in, FILE_EXTDATA_FUNC f_extdata, void *f_extdata_args, FILE_EXTDATA_ITEM_FUNC f_item, void *f_item_args, bool for_write, FILE_EXTENSIBLE_DATA **extdata_out, PAGE_PTR *page_out)
static int file_temp_alloc(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, VPID *vpid_alloc_out)
#define LSA_INITIALIZER
Definition: log_lsa.hpp:76
static int file_extdata_find_nth_vpid_and_skip_marked(THREAD_ENTRY *thread_p, const void *data, int index, bool *stop, void *args)
#define assert_release(e)
Definition: error_manager.h:96
STATIC_INLINE void file_tempcache_free_entry_list(FILE_TEMPCACHE_ENTRY **list)
void pgbuf_set_dirty(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, bool free_page)
Definition: page_buffer.c:4280
FILE_TEMPCACHE_ENTRY ** tran_files
Definition: file_manager.c:494
static int file_tracker_register_internal(THREAD_ENTRY *thread_p, PAGE_PTR page_track_head, const FILE_TRACK_ITEM *item)
int thread_get_current_entry_index(void)
#define VFID_AS_ARGS(vfidp)
Definition: dbtype_def.h:892
int file_rv_partsect_set(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
STATIC_INLINE void file_extdata_append(FILE_EXTENSIBLE_DATA *extdata, const void *append_data) __attribute__((ALWAYS_INLINE))
#define FILE_TEMPCACHE_AS_ARGS
Definition: file_manager.c:381
INT16 VOLID
int lock_object(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock, int cond_flag)
void log_sysop_start(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3578
int heap_dump_capacity(THREAD_ENTRY *thread_p, FILE *fp, const HFID *hfid)
Definition: heap_file.c:14281
#define FILE_USER_PAGE_MARK_DELETED(vpid)
Definition: file_manager.c:447
#define FILE_FLAG_NUMERABLE
Definition: file_manager.c:164
STATIC_INLINE void file_extdata_remove_at(FILE_EXTENSIBLE_DATA *extdata, int position, int count) __attribute__((ALWAYS_INLINE))
STATIC_INLINE void file_tempcache_dump(FILE *fp)
#define FILE_TRACK_ITEM_AS_ARGS(item)
Definition: file_manager.c:390
#define OID_SET_NULL(oidp)
Definition: oid.h:85
int(* FILE_EXTDATA_FUNC)(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, bool *stop, void *args)
Definition: file_manager.c:247
int(* FILE_MAP_PAGE_FUNC)(THREAD_ENTRY *thread_p, PAGE_PTR *page, bool *stop, void *args)
Definition: file_manager.h:152
int disk_compare_vsids(const void *first, const void *second)
#define FILE_TEMPCACHE_ENTRY_MSG
Definition: file_manager.c:386
int vacuum_is_file_dropped(THREAD_ENTRY *thread_p, bool *is_file_dropped, VFID *vfid, MVCCID mvccid)
Definition: vacuum.c:6485
#define VSID_IS_SECTOR_OF_VPID(vsid, vpid)
static int file_set_tde_algorithm(THREAD_ENTRY *thread_p, const VFID *vfid, TDE_ALGORITHM tde_algo)
int32_t pageid
Definition: dbtype_def.h:879
STATIC_INLINE void file_partsect_clear_bit(FILE_PARTIAL_SECTOR *partsect, int offset) __attribute__((ALWAYS_INLINE))
INT32 root_pageid
void file_rv_dump_vfid_and_vpid(FILE *fp, int length, void *data)
#define LSA_AS_ARGS(lsa_ptr)
Definition: log_lsa.hpp:78
static int file_tracker_item_dump_capacity(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
INT32 hpgid
INT32 reserved2
Definition: file_manager.c:156
PGBUF_LATCH_CONDITION latch_cond
Definition: file_manager.c:424
static int file_extdata_find_nth_vpid(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, bool *stop, void *args)
int file_get_sticky_first_page(THREAD_ENTRY *thread_p, const VFID *vfid, VPID *vpid_out)
#define FILE_HEADER_GET_USER_PAGE_FTAB(fh, pagetab)
Definition: file_manager.c:201
#define VPID_INITIALIZER
Definition: dbtype_def.h:894
static void file_set_tde_algorithm_internal(FILE_HEADER *fhead, TDE_ALGORITHM tde_algo)
int file_rv_user_page_unmark_delete_physical(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
PAGE_TYPE
int(* FILE_TRACK_ITEM_FUNC)(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
Definition: file_manager.c:556
STATIC_INLINE void * file_extdata_start(const FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
#define FILE_ALLOC_TYPE_STRING(alloc_type)
Definition: file_manager.c:374
#define OID_AS_ARGS(oidp)
Definition: oid.h:39
static bool file_tempcache_check_duplicate(THREAD_ENTRY *thread_p, FILE_TEMPCACHE_ENTRY *entry, bool is_numerable)
STATIC_INLINE int file_init_page_type_internal(THREAD_ENTRY *thread_p, PAGE_PTR page, PAGE_TYPE ptype, bool is_temp) __attribute__((ALWAYS_INLINE))
#define FILE_HEADER_ALIGNED_SIZE
Definition: file_manager.c:161
int disk_unreserve_ordered_sectors(THREAD_ENTRY *thread_p, DB_VOLPURPOSE purpose, int nsects, VSID *vsids)
void log_sysop_end_logical_undo(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, int undo_size, const char *undo_data)
Definition: log_manager.c:3920
#define er_log_debug(...)
INT64 time_creation
Definition: file_manager.c:86
#define VPID_AS_ARGS(vpidp)
Definition: dbtype_def.h:896
int file_rv_dealloc_on_undo(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
static TDE_ALGORITHM file_get_tde_algorithm_internal(const FILE_HEADER *fhead)
int file_dump(THREAD_ENTRY *thread_p, const VFID *vfid, FILE *fp)
static int file_extdata_find_not_full(THREAD_ENTRY *thread_p, FILE_EXTENSIBLE_DATA **extdata, PAGE_PTR *page_out, bool *found)
STATIC_INLINE void file_header_alloc(FILE_HEADER *fhead, FILE_ALLOC_TYPE alloc_type, bool was_empty, bool is_full) __attribute__((ALWAYS_INLINE))
#define NULL_VOLDES
Definition: file_io.h:44
#define FILE_FULL_PAGE_BITMAP
Definition: file_manager.c:267
FILE_TEMPCACHE_ENTRY * free_entries
Definition: file_manager.c:479
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
#define FILE_EXTDATA_MSG(name)
Definition: file_manager.c:365
int file_create_ehash_dir(THREAD_ENTRY *thread_p, int npages, bool is_tmp, FILE_EHASH_DES *des_ehash, VFID *vfid)
static int file_perm_alloc(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, VPID *vpid_alloc_out)
STATIC_INLINE void * file_extdata_at(const FILE_EXTENSIBLE_DATA *extdata, int index) __attribute__((ALWAYS_INLINE))
static int file_user_page_table_item_dump(THREAD_ENTRY *thread_p, const void *data, int index, bool *stop, void *args)
static int file_user_page_table_extdata_dump(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, bool *stop, void *args)
int file_rv_user_page_mark_delete(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
int file_create_with_npages(THREAD_ENTRY *thread_p, FILE_TYPE file_type, int npages, FILE_DESCRIPTORS *des, VFID *vfid)
#define VFID_ISNULL(vfid_ptr)
Definition: file_manager.h:72
void THREAD_ENTRY
struct file_tempcache FILE_TEMPCACHE
Definition: file_manager.c:476
FILE_TRACK_HEAP_METADATA heap
Definition: file_manager.c:519
#define pgbuf_unfix_and_init(thread_p, pgptr)
Definition: page_buffer.h:63
static int file_table_collect_vsid(THREAD_ENTRY *thread_p, const void *item, int index_unused, bool *stop, void *args)
int file_rv_tracker_mark_heap_deleted_compensate_or_run_postpone(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
int file_rv_extdata_set_next(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
INT32 reserved0
Definition: file_manager.c:154
void file_tempcache_drop_tran_temp_files(THREAD_ENTRY *thread_p)
DISK_ISVALID disk_check_sectors_are_reserved(THREAD_ENTRY *thread_p, VSID *vsids, int nsects)
STATIC_INLINE void file_log_extdata_remove(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, PAGE_PTR page, int position, int count) __attribute__((ALWAYS_INLINE))
#define FREE(PTR)
Definition: cas_common.h:56
INT32 reserved1
Definition: file_manager.c:155
static int file_extdata_func_for_search_ordered(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, bool *stop, void *args)
int file_tracker_interruptable_iterate(THREAD_ENTRY *thread_p, FILE_TYPE desired_ftype, VFID *vfid, OID *class_oid)
static int file_extdata_all_item_count(THREAD_ENTRY *thread_p, FILE_EXTENSIBLE_DATA *extdata, int *count)
int file_descriptor_get(THREAD_ENTRY *thread_p, const VFID *vfid, FILE_DESCRIPTORS *desc_out)
int btree_dump_capacity(THREAD_ENTRY *thread_p, FILE *fp, BTID *btid)
Definition: btree.c:8734
PAGE_TYPE pgbuf_get_page_ptype(THREAD_ENTRY *thread_p, PAGE_PTR pgptr)
Definition: page_buffer.c:4675
int heap_get_class_tde_algorithm(THREAD_ENTRY *thread_p, const OID *class_oid, TDE_ALGORITHM *tde_algo)
Definition: heap_file.c:10737
int file_alloc_sticky_first_page(THREAD_ENTRY *thread_p, const VFID *vfid, FILE_INIT_PAGE_FUNC f_init, void *f_init_args, VPID *vpid_out, PAGE_PTR *page_out)
const char * tde_get_algorithm_name(TDE_ALGORITHM tde_algo)
Definition: tde.c:1694
#define SECTOR_FROM_PAGEID(pageid)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
#define FILE_HEAD_FULL_MSG
Definition: file_manager.c:346
static int file_compare_track_items(const void *first, const void *second)
STATIC_INLINE void file_header_sanity_check(THREAD_ENTRY *thread_p, FILE_HEADER *fhead) __attribute__((ALWAYS_INLINE))
Definition: file_manager.c:933
int file_rv_fhead_alloc(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
PAGE_PTR pgptr
Definition: recovery.h:199
#define assert(x)
int ncached_not_numerable
Definition: file_manager.c:486
static int file_perm_dealloc(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, const VPID *vpid_dealloc, FILE_ALLOC_TYPE alloc_type)
TDE_ALGORITHM
Definition: tde.h:71
int32_t fileid
Definition: dbtype_def.h:886
bool pgbuf_check_page_ptype(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, PAGE_TYPE ptype)
int file_get_num_user_pages(THREAD_ENTRY *thread_p, const VFID *vfid, int *n_user_pages_out)
static int file_perm_expand(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead)
static int file_tracker_apply_to_file(THREAD_ENTRY *thread_p, const VFID *vfid, PGBUF_LATCH_MODE mode, FILE_TRACK_ITEM_FUNC func, void *args)
#define FILE_TABLESPACE_AS_ARGS(tabspace)
Definition: file_manager.c:326
int prm_get_integer_value(PARAM_ID prm_id)
#define pgbuf_set_dirty_and_free(thread_p, pgptr)
Definition: page_buffer.h:351
int spacedb(UTIL_FUNCTION_ARG *arg)
Definition: util_cs.c:844
#define STATIC_INLINE
LOG_LSA * pgbuf_get_lsa(PAGE_PTR pgptr)
Definition: page_buffer.c:4318
static bool file_Logging
Definition: file_manager.c:314
PGBUF_LATCH_MODE
Definition: page_buffer.h:176
int file_tracker_dump_all_btree_capacities(THREAD_ENTRY *thread_p, FILE *fp)
void file_rv_dump_extdata_set_next(FILE *fp, int ignore_length, void *data)
STATIC_INLINE void file_tempcache_cache_or_drop_entries(THREAD_ENTRY *thread_p, FILE_TEMPCACHE_ENTRY **entries)
VPID vpid_last_temp_alloc
Definition: file_manager.c:126
Definition: file_manager.c:468
static int file_rv_partsect_update(THREAD_ENTRY *thread_p, LOG_RCV *rcv, bool set)
int file_apply_tde_algorithm(THREAD_ENTRY *thread_p, const VFID *vfid, const TDE_ALGORITHM tde_algo)
#define UNDO_DATA_SIZE
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
void log_append_undo_data(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int length, const void *data)
Definition: log_manager.c:1917
static int file_partial_table_item_dump(THREAD_ENTRY *thread_p, const void *data, int index, bool *stop, void *args)
TDE_CIPHER tde_Cipher
Definition: tde.c:69
int n_sector_empty
Definition: file_manager.c:104
INT16 offset_to_full_ftab
Definition: file_manager.c:114
int n_page_mark_delete
Definition: file_manager.c:98
PGBUF_LATCH_CONDITION
Definition: page_buffer.h:185
#define FILE_USER_PAGE_CLEAR_MARK_DELETED(vpid)
Definition: file_manager.c:448
int heap_get_hfid_from_vfid(THREAD_ENTRY *thread_p, const VFID *vfid, HFID *hfid)
Definition: heap_file.c:24843
#define FILE_NUMERABLE_REGULAR_STRING(is_numerable)
Definition: file_manager.c:322
FILE_TYPE ftype
Definition: file_manager.c:471
static int file_table_append_full_sector_page(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, const VPID *vpid_new)
#define FILE_HEADER_GET_PART_FTAB(fh, parttab)
Definition: file_manager.c:192
#define FILE_RV_DEALLOC_COMPENSATE
Definition: file_manager.c:406
int xfile_apply_tde_to_class_files(THREAD_ENTRY *thread_p, const OID *class_oid)
static int file_tracker_item_dump_heap(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
STATIC_INLINE int file_tempcache_alloc_entry(FILE_TEMPCACHE_ENTRY **entry)
#define pgbuf_promote_read_latch(thread_p, pgptr_p, condition)
Definition: page_buffer.h:270
UINT64 bit64_clear(UINT64 i, int off)
Definition: bit.c:587
int file_get_tde_algorithm(THREAD_ENTRY *thread_p, const VFID *vfid, PGBUF_LATCH_CONDITION fix_head_cond, TDE_ALGORITHM *tde_algo)
int file_tracker_dump_all_capacities(THREAD_ENTRY *thread_p, FILE *fp)
STATIC_INLINE int file_tempcache_get(THREAD_ENTRY *thread_p, FILE_TYPE ftype, bool numerable, FILE_TEMPCACHE_ENTRY **entry)
void lock_unlock_object(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock, bool force)
FILE_TYPE type
Definition: file_manager.c:107
void log_append_compensate_with_undo_nxlsa(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VPID *vpid, PGLENGTH offset, PAGE_PTR pgptr, int length, const void *data, LOG_TDES *tdes, const LOG_LSA *undo_nxlsa)
Definition: log_manager.c:2990
static enum scanner_mode mode
INT16 offset_to_partial_ftab
Definition: file_manager.c:113
#define VPID_EQ(vpid_ptr1, vpid_ptr2)
Definition: dbtype_def.h:915
#define VFID_INITIALIZER
Definition: dbtype_def.h:890
STATIC_INLINE void file_header_update_mark_deleted(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, int delta) __attribute__((ALWAYS_INLINE))
STATIC_INLINE int file_header_copy(THREAD_ENTRY *thread_p, const VFID *vfid, FILE_HEADER *fhead_copy) __attribute__((ALWAYS_INLINE))
#define HFID_SET_NULL(hfid)
#define FILE_TEMPCACHE_MSG
Definition: file_manager.c:377
STATIC_INLINE bool file_table_collector_has_page(FILE_FTAB_COLLECTOR *collector, VPID *vpid) __attribute__((ALWAYS_INLINE))
short volid
Definition: dbtype_def.h:880
void log_append_compensate(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VPID *vpid, PGLENGTH offset, PAGE_PTR pgptr, int length, const void *data, LOG_TDES *tdes)
Definition: log_manager.c:2964
FILE_TABLESPACE tablespace
Definition: file_manager.c:89
STATIC_INLINE FILE_TEMPCACHE_ENTRY * file_tempcache_pop_tran_file(THREAD_ENTRY *thread_p, const VFID *vfid)
STATIC_INLINE void file_log_fhead_dealloc(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, bool is_empty, bool was_full) __attribute__((ALWAYS_INLINE))
static DISK_ISVALID file_table_check(THREAD_ENTRY *thread_p, const VFID *vfid, DISK_VOLMAP_CLONE *disk_map_clone)
static VPID file_Tracker_vpid
Definition: file_manager.c:507
TDE_ALGORITHM pgbuf_get_tde_algorithm(PAGE_PTR pgptr)
Definition: page_buffer.c:4548
#define heap_classrepr_free_and_init(class_repr, idxp)
Definition: heap_file.h:91
VFID vfid
int length
Definition: recovery.h:202
FILE_TEMPCACHE_ENTRY * cached_not_numerable
Definition: file_manager.c:483
STATIC_INLINE int file_partsect_pageid_to_offset(FILE_PARTIAL_SECTOR *partsect, PAGEID pageid) __attribute__((ALWAYS_INLINE))
#define FILE_PARTSECT_AS_ARGS(ps)
Definition: file_manager.c:372
#define NULL
Definition: freelistheap.h:34
static void file_tempcache_final(void)
#define PGBUF_PAGE_MODIFY_MSG(name)
Definition: page_buffer.h:59
int file_alloc(THREAD_ENTRY *thread_p, const VFID *vfid, FILE_INIT_PAGE_FUNC f_init, void *f_init_args, VPID *vpid_out, PAGE_PTR *page_out)
void file_temp_preserve(THREAD_ENTRY *thread_p, const VFID *vfid)
FILE_PARTIAL_SECTOR * partsect_ftab
Definition: file_manager.c:414
#define FILE_TRACK_ITEM_MSG
Definition: file_manager.c:389
#define ER_PAGE_LATCH_PROMOTE_FAIL
Definition: error_code.h:1512
UINT64 MVCCID
STATIC_INLINE void file_extdata_insert_at(FILE_EXTENSIBLE_DATA *extdata, int position, int count, const void *data) __attribute__((ALWAYS_INLINE))
UINT64 bit64_set(UINT64 i, int off)
Definition: bit.c:579
FILE_FTAB_COLLECTOR ftab_collector
Definition: file_manager.c:425
if(extra_options)
Definition: dynamic_load.c:958
int logtb_get_current_tran_index(void)
void log_append_run_postpone(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, const VPID *rcv_vpid, int length, const void *data, const LOG_LSA *ref_lsa)
Definition: log_manager.c:2860
VFID vfid
#define PGBUF_PAGE_MODIFY_ARGS(pg, prev_lsa)
Definition: page_buffer.h:60
DKNPAGES npage_user
STATIC_INLINE void file_extdata_update_item(THREAD_ENTRY *thread_p, PAGE_PTR page_extdata, const void *item_newval, int index_item, FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
static int file_tracker_item_dump_heap_capacity(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
bool LSA_ISNULL(const log_lsa *lsa_ptr)
Definition: log_lsa.hpp:153
int file_create_heap(THREAD_ENTRY *thread_p, bool reuse_oid, const OID *class_oid, VFID *vfid)
PAGE_PTR pgptr
Definition: log_append.hpp:57
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
static int file_compare_vpids(const void *first, const void *second)
#define FILE_FLAG_TEMPORARY
Definition: file_manager.c:165
void log_append_undoredo_data(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int undo_length, int redo_length, const void *undo_data, const void *redo_data)
Definition: log_manager.c:1837
#define pgbuf_fix(thread_p, vpid, fetch_mode, requestmode, condition)
Definition: page_buffer.h:255
SPACEDB_FILES spacedb_temp
Definition: file_manager.c:497
#define FILE_CACHE_LAST_FIND_NTH(fh)
Definition: file_manager.c:175
static int file_tracker_init_page(THREAD_ENTRY *thread_p, PAGE_PTR page, void *args)
#define file_log(func, msg,...)
Definition: file_manager.c:316
STATIC_INLINE void file_header_dealloc(FILE_HEADER *fhead, FILE_ALLOC_TYPE alloc_type, bool is_empty, bool was_full) __attribute__((ALWAYS_INLINE))
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
STATIC_INLINE bool file_partsect_is_empty(FILE_PARTIAL_SECTOR *partsect) __attribute__((ALWAYS_INLINE))
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
STATIC_INLINE bool file_extdata_can_merge(const FILE_EXTENSIBLE_DATA *extdata_src, const FILE_EXTENSIBLE_DATA *extdata_dest) __attribute__((ALWAYS_INLINE))
static int file_extdata_collect_ftab_pages(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, bool *stop, void *args)
#define NULL_OFFSET
int file_create_temp(THREAD_ENTRY *thread_p, int npages, VFID *vfid)
int file_temp_retire_preserved(THREAD_ENTRY *thread_p, const VFID *vfid)
bool logtb_set_check_interrupt(THREAD_ENTRY *thread_p, bool flag)
#define CEIL_PTVDIV(dividend, divisor)
Definition: memory_alloc.h:50
OR_CLASSREP * heap_classrepr_get(THREAD_ENTRY *thread_p, const OID *class_oid, RECDES *class_recdes, REPR_ID reprid, int *idx_incache)
Definition: heap_file.c:2299
VFID * heap_ovf_find_vfid(THREAD_ENTRY *thread_p, const HFID *hfid, VFID *ovf_vfid, bool docreate, PGBUF_LATCH_CONDITION latch_cond)
Definition: heap_file.c:6353
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
STATIC_INLINE bool file_partsect_is_bit_set(FILE_PARTIAL_SECTOR *partsect, int offset) __attribute__((ALWAYS_INLINE))
static int file_tracker_item_spacedb(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
#define HFID_AS_ARGS(hfid)
void pgbuf_get_vpid(PAGE_PTR pgptr, VPID *vpid)
Definition: page_buffer.c:4579
offset_type offset
Definition: log_append.hpp:58
int file_rv_tracker_reuse_heap(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
#define VFID_COPY(vfid_ptr1, vfid_ptr2)
Definition: file_manager.h:69
const char * file_type_to_string(FILE_TYPE fstruct_type)
void log_sysop_abort(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4017
#define NULL_REPRID
FILE_HEAP_DES heap
Definition: file_manager.h:132
void er_stack_pop(void)
static int file_tracker_item_dump_btree_capacity(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
LOG_LSA reference_lsa
Definition: recovery.h:204
static VFID file_Tracker_vfid
Definition: file_manager.c:506
void file_rv_dump_extdata_remove(FILE *fp, int length, void *data)
MVCCID logtb_get_current_mvccid(THREAD_ENTRY *thread_p)
STATIC_INLINE int file_table_collect_ftab_pages(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, bool collect_numerable, FILE_FTAB_COLLECTOR *collector_out) __attribute__((ALWAYS_INLINE))
DB_VOLPURPOSE
Definition: dbtype_def.h:185
int file_descriptor_dump(THREAD_ENTRY *thread_p, const VFID *vfid, FILE *fp)
int file_init_page_type(THREAD_ENTRY *thread_p, PAGE_PTR page, void *args)
pthread_mutex_t mutex
Definition: file_manager.c:489
void log_append_postpone(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int length, const void *data)
Definition: log_manager.c:2698
#define VPID_ISNULL(vpid_ptr)
Definition: dbtype_def.h:925
STATIC_INLINE void file_tempcache_check_lock(void)
const char * data
Definition: recovery.h:203
STATIC_INLINE INT16 file_extdata_item_count(const FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
void file_rv_dump_extdata_add(FILE *fp, int length, void *data)
STATIC_INLINE void perfmon_inc_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid) __attribute__((ALWAYS_INLINE))
void file_postpone_destroy(THREAD_ENTRY *thread_p, const VFID *vfid)
LOG_TDES * LOG_FIND_CURRENT_TDES(THREAD_ENTRY *thread_p=NULL)
Definition: log_impl.h:1115
bool log_check_system_op_is_started(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4166
int file_rv_perm_expand_undo(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
int file_tracker_dump(THREAD_ENTRY *thread_p, FILE *fp)
STATIC_INLINE void file_partsect_set_bit(FILE_PARTIAL_SECTOR *partsect, int offset) __attribute__((ALWAYS_INLINE))
int offset_to_last_temp_alloc
Definition: file_manager.c:127
int file_rv_destroy(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
#define ARG_FILE_LINE
Definition: error_manager.h:44
STATIC_INLINE int file_extdata_size(const FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
int file_rv_user_page_unmark_delete_logical(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
UINT64 FILE_ALLOC_BITMAP
Definition: file_manager.c:266
STATIC_INLINE bool file_partsect_alloc(FILE_PARTIAL_SECTOR *partsect, VPID *vpid_out, int *offset_out) __attribute__((ALWAYS_INLINE))
static void file_print_name_of_class(THREAD_ENTRY *thread_p, FILE *fp, const OID *class_oid_p)
static FILE_TEMPCACHE * file_Tempcache
Definition: file_manager.c:500
#define FILE_TYPE_CAN_BE_NUMERABLE(ftype)
Definition: file_manager.c:179
static int file_extdata_add_item_count(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, bool *stop, void *args)
int n_sector_partial
Definition: file_manager.c:102
int file_create_ehash(THREAD_ENTRY *thread_p, int npages, bool is_tmp, FILE_EHASH_DES *des_ehash, VFID *vfid)
#define FILE_EMPTY_PAGE_BITMAP
Definition: file_manager.c:268
STATIC_INLINE int file_extdata_max_size(const FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
INT16 PGLENGTH
DKNPAGES npage_reserved
#define FILE_IS_TEMPORARY(fh)
Definition: file_manager.c:172
#define FILE_TABLESPACE_FOR_TEMP_NPAGES(tabspace, npages)
Definition: file_manager.c:298
static int file_tracker_register(THREAD_ENTRY *thread_p, const VFID *vfid, FILE_TYPE ftype, FILE_TRACK_METADATA *metadata)
static int file_compare_vfids(const void *first, const void *second)
#define free_and_init(ptr)
Definition: memory_alloc.h:147
int32_t sectid
Definition: dbtype_def.h:930
STATIC_INLINE bool file_tempcache_put(THREAD_ENTRY *thread_p, FILE_TEMPCACHE_ENTRY *entry)
#define LOG_ISRESTARTED()
Definition: log_impl.h:232
#define DB_ALIGN(offset, align)
Definition: memory_alloc.h:84
static int file_full_table_item_dump(THREAD_ENTRY *thread_p, const void *data, int index, bool *stop, void *args)
static int file_table_move_partial_sectors_to_header(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, VPID *vpid_alloc_out)
#define VSID_FROM_VPID(vsid, vpid)
void heap_dump(THREAD_ENTRY *thread_p, FILE *fp, HFID *hfid, bool dump_records)
Definition: heap_file.c:14113
#define FILE_EXTDATA_HEADER_ALIGNED_SIZE
Definition: file_manager.c:233
#define FILE_FLAG_ENCRYPTED_MASK
Definition: file_manager.c:169
int n_page_total
Definition: file_manager.c:93
#define const
Definition: cnvlex.c:77
STATIC_INLINE void file_extdata_merge_unordered(const FILE_EXTENSIBLE_DATA *extdata_src, FILE_EXTENSIBLE_DATA *extdata_dest) __attribute__((ALWAYS_INLINE))
int file_rv_extdata_remove(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
#define DB_SECTORSIZE
int btree_get_btid_from_file(THREAD_ENTRY *thread_p, const VFID *vfid, BTID *btid_out)
Definition: btree.c:6930
#define DB_PAGESIZE
STATIC_INLINE void file_header_init(FILE_HEADER *fhead) __attribute__((ALWAYS_INLINE))
Definition: file_manager.c:885
STATIC_INLINE void file_extdata_append_array(FILE_EXTENSIBLE_DATA *extdata, const void *append_data, INT16 count) __attribute__((ALWAYS_INLINE))
static int file_table_check_page_is_in_sectors(THREAD_ENTRY *thread_p, const void *data, int index, bool *stop, void *args)
void pgbuf_set_page_ptype(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, PAGE_TYPE ptype)
Definition: page_buffer.c:4847
FILE_MAP_PAGE_FUNC func
Definition: file_manager.c:429
bool prm_get_bool_value(PARAM_ID prm_id)
bool is_loaded
Definition: tde.h:148
int file_rv_tracker_mark_heap_deleted(THREAD_ENTRY *thread_p, LOG_RCV *rcv, bool is_undo)
FILE_EHASH_DES ehash
Definition: file_manager.h:136
STATIC_INLINE int file_temp_retire_internal(THREAD_ENTRY *thread_p, const VFID *vfid, bool was_preserved) __attribute__((ALWAYS_INLINE))
#define FILE_EXTDATA_AS_ARGS(extdata)
Definition: file_manager.c:367
FILE_DESCRIPTORS descriptor
Definition: file_manager.c:90
void er_clear(void)
static int file_partial_table_extdata_dump(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata, bool *stop, void *args)
void log_sysop_attach_to_outer(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4076
void log_sysop_commit(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3895
static int file_extdata_item_func_for_search(THREAD_ENTRY *thread_p, const void *item, int index, bool *stop, void *args)
static int file_sector_map_pages(THREAD_ENTRY *thread_p, const void *data, int index, bool *stop, void *args)
int file_get_tran_num_temp_files(THREAD_ENTRY *thread_p)
#define FILE_FLAG_ENCRYPTED_ARIA
Definition: file_manager.c:167
STATIC_INLINE void file_tempcache_retire_entry(FILE_TEMPCACHE_ENTRY *entry)
STATIC_INLINE int file_table_collect_all_vsids(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, FILE_VSID_COLLECTOR *collector_out) __attribute__((ALWAYS_INLINE))
int i
Definition: dynamic_load.c:954
int file_rv_set_tde_algorithm(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
INT16 offset_to_user_page_ftab
Definition: file_manager.c:115
#define VSID_AS_ARGS(vsidp)
Definition: dbtype_def.h:934
FILE_OVF_BTREE_DES btree_key_overflow
Definition: file_manager.h:135
STATIC_INLINE int file_temp_set_type(THREAD_ENTRY *thread_p, VFID *vfid, FILE_TYPE ftype) __attribute__((ALWAYS_INLINE))
int file_rv_fhead_convert_ftab_to_user_page(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
int file_create_query_area(THREAD_ENTRY *thread_p, VFID *vfid)
DKNPAGES npage_ftab
int file_rv_perm_expand_redo(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
static int file_tracker_item_reuse_heap(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
#define FILE_GET_HEADER_VPID(vfid, vpid)
Definition: file_manager.c:189
STATIC_INLINE bool file_extdata_merge_pages(THREAD_ENTRY *thread_p, const FILE_EXTENSIBLE_DATA *extdata_src, const PAGE_PTR page_src, FILE_EXTENSIBLE_DATA *extdata_dest, PAGE_PTR page_dest, int(*compare_func)(const void *, const void *), bool ordered) __attribute__((ALWAYS_INLINE))
int file_rv_header_update_mark_deleted(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
#define NULL_VOLID
static int file_tracker_item_mark_heap_deleted(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
FILE_ALLOC_TYPE
Definition: file_manager.c:399
#define pthread_mutex_lock(a)
Definition: area_alloc.c:50
STATIC_INLINE int file_create_temp_internal(THREAD_ENTRY *thread_p, int npages, FILE_TYPE ftype, bool is_numerable, VFID *vfid_out) __attribute__((ALWAYS_INLINE))
VOLID volid_last_expand
Definition: file_manager.c:111
static int file_sector_map_dealloc(THREAD_ENTRY *thread_p, const void *data, int index, bool *stop, void *args)
#define FILE_FTAB_COLLECTOR_INITIALIZER
Definition: file_manager.c:416
short volid
Definition: dbtype_def.h:931
#define VSID_EQ(first, second)
Definition: disk_manager.h:44
#define FILE_TABLESPACE_MSG
Definition: file_manager.c:324
bool pgbuf_has_any_waiters(PAGE_PTR pgptr)
PGBUF_LATCH_MODE latch_mode
Definition: file_manager.c:423
short volid
Definition: dbtype_def.h:887
void log_sysop_end_logical_run_postpone(THREAD_ENTRY *thread_p, LOG_LSA *posp_lsa)
Definition: log_manager.c:3982
#define FILE_TABLESPACE_FOR_PERM_NPAGES(tabspace, npages)
Definition: file_manager.c:292
#define PGBUF_PAGE_LSA_AS_ARGS(pg)
Definition: page_buffer.h:54
FILE_TEMPCACHE_ENTRY * cached_numerable
Definition: file_manager.c:484
int(* FILE_INIT_PAGE_FUNC)(THREAD_ENTRY *thread_p, PAGE_PTR page, void *args)
Definition: file_manager.h:151
int file_tracker_create(THREAD_ENTRY *thread_p, VFID *vfid_tracker_out)
#define PGBUF_PAGE_STATE_MSG(name)
Definition: page_buffer.h:56
INT32 PAGEID
#define OID_ISNULL(oidp)
Definition: oid.h:81
#define DONT_FREE
Definition: page_buffer.h:41
FILE_OVF_HEAP_DES heap_overflow
Definition: file_manager.h:133
#define FILE_DESCRIPTORS_SIZE
Definition: file_manager.h:128
STATIC_INLINE void file_extdata_merge_ordered(const FILE_EXTENSIBLE_DATA *extdata_src, FILE_EXTENSIBLE_DATA *extdata_dest, int(*compare_func)(const void *, const void *)) __attribute__((ALWAYS_INLINE))
SPACEDB_FILE_TYPE
int heap_get_indexinfo_of_btid(THREAD_ENTRY *thread_p, const OID *class_oid, const BTID *btid, BTREE_TYPE *type, int *num_attrs, ATTR_ID **attr_ids, int **attrs_prefix_length, char **btnamepp, int *func_index_col_id)
Definition: heap_file.c:13134
STATIC_INLINE void file_header_dump(THREAD_ENTRY *thread_p, const FILE_HEADER *fhead, FILE *fp) __attribute__((ALWAYS_INLINE))
STATIC_INLINE void file_log_fhead_alloc(THREAD_ENTRY *thread_p, PAGE_PTR page_fhead, FILE_ALLOC_TYPE alloc_type, bool was_empty, bool is_full) __attribute__((ALWAYS_INLINE))
void file_manager_final(void)
Definition: file_manager.c:869
int file_rv_fhead_set_last_user_page_ftab(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
int heap_get_class_info(THREAD_ENTRY *thread_p, const OID *class_oid, HFID *hfid_out, FILE_TYPE *ftype_out, char **classname_out)
Definition: heap_file.c:16733
const void * data
Definition: log_append.hpp:48
#define FILE_GET_TRACKER_LOCK_MODE(file_type)
Definition: file_manager.c:562
#define FILE_FLAG_ENCRYPTED_AES
Definition: file_manager.c:166
int file_rv_tracker_unregister_undo(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
#define FILE_HEAD_ALLOC_AS_ARGS(fhead)
Definition: file_manager.c:338
int heap_get_class_name(THREAD_ENTRY *thread_p, const OID *class_oid, char **class_name)
Definition: heap_file.c:9328
#define ER_TDE_CIPHER_IS_NOT_LOADED
Definition: error_code.h:1613
static int file_rv_dealloc_internal(THREAD_ENTRY *thread_p, LOG_RCV *rcv, bool compensate_or_run_postpone)
#define FILE_PARTIAL_SECTOR_INITIALIZER
Definition: file_manager.c:281
FILE_ALLOC_BITMAP page_bitmap
Definition: file_manager.c:279
SECTID DKNSECTS
STATIC_INLINE bool file_extdata_is_empty(const FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
#define VPID_SET_NULL(vpid_ptr)
Definition: dbtype_def.h:906
STATIC_INLINE void file_tempcache_unlock(void)
int file_tracker_dump_all_heap(THREAD_ENTRY *thread_p, FILE *fp, bool dump_records)
void pgbuf_set_tde_algorithm(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, TDE_ALGORITHM tde_algo, bool skip_logging)
Definition: page_buffer.c:4473
#define PGBUF_PAGE_STATE_ARGS(pg)
Definition: page_buffer.h:57
STATIC_INLINE void file_extdata_init(INT16 item_size, INT16 max_size, FILE_EXTENSIBLE_DATA *extdata) __attribute__((ALWAYS_INLINE))
static int file_tracker_map(THREAD_ENTRY *thread_p, PGBUF_LATCH_MODE latch_mode, FILE_TRACK_ITEM_FUNC func, void *args)
int file_is_temp(THREAD_ENTRY *thread_p, const VFID *vfid, bool *is_temp)
#define FILE_ALLOC_BITMAP_NBITS
Definition: file_manager.c:270
FILE_TEMPCACHE_ENTRY * next
Definition: file_manager.c:473
#define VFID_SET_NULL(vfid_ptr)
Definition: file_manager.h:65
const char ** p
Definition: dynamic_load.c:945
static int file_tracker_spacedb(THREAD_ENTRY *thread_p, SPACEDB_FILES *spacedb)
VPID * pgbuf_get_vpid_ptr(PAGE_PTR pgptr)
Definition: page_buffer.c:4609
DISK_ISVALID
Definition: disk_manager.h:53
int util_bsearch(const void *key, const void *base, int n_elems, unsigned int sizeof_elem, int(*func_compare)(const void *, const void *), bool *out_found)
Definition: util_func.c:764
int file_tracker_dump_all_heap_capacities(THREAD_ENTRY *thread_p, FILE *fp)
#define DISK_SECTOR_NPAGES
static int file_tracker_item_dump(THREAD_ENTRY *thread_p, PAGE_PTR page_of_item, FILE_EXTENSIBLE_DATA *extdata, int index_item, bool *stop, void *args)
DISK_ISVALID file_tracker_check(THREAD_ENTRY *thread_p)
int first_index_find_nth_last
Definition: file_manager.c:151
bool bit64_is_set(UINT64 i, int off)
Definition: bit.c:572
#define ER_CANNOT_CHECK_FILE
Definition: error_code.h:1541
static int file_file_map_set_tde_algorithm(THREAD_ENTRY *thread_p, PAGE_PTR *page, bool *stop, void *args)
#define pthread_mutex_destroy(a)
Definition: area_alloc.c:49
int file_rv_dealloc_on_postpone(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
int file_map_pages(THREAD_ENTRY *thread_p, const VFID *vfid, PGBUF_LATCH_MODE latch_mode, PGBUF_LATCH_CONDITION latch_cond, FILE_MAP_PAGE_FUNC func, void *args)
#define FILE_HEAD_FULL_AS_ARGS(fhead)
Definition: file_manager.c:355
static void file_extdata_find_ordered(const FILE_EXTENSIBLE_DATA *extdata, const void *item_to_find, int(*compare_func)(const void *, const void *), bool *found, int *position)