CUBRID Engine  latest
btree_load.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  * btree_load.c - B+-Tree Loader
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 
31 #include "btree_load.h"
32 
33 #include "btree.h"
34 #include "dbtype.h"
35 #include "external_sort.h"
36 #include "heap_file.h"
37 #include "log_append.hpp"
38 #include "log_manager.h"
39 #include "memory_alloc.h"
41 #include "mvcc.h"
42 #include "object_primitive.h"
43 #include "object_representation.h"
45 #include "partition.h"
46 #include "partition_sr.h"
47 #include "query_executor.h"
48 #include "query_opfunc.h"
49 #include "server_support.h"
50 #include "stream_to_xasl.h"
51 #include "thread_manager.hpp"
52 #include "thread_entry_task.hpp"
53 #include "xserver_interface.h"
54 #include "xasl.h"
55 #include "xasl_unpack_info.hpp"
56 
57 typedef struct sort_args SORT_ARGS;
58 struct sort_args
59 { /* Collection of information required for "sr_index_sort" */
60  int unique_pk;
62  HFID *hfids; /* Array of HFIDs for the class(es) */
63  OID *class_ids; /* Array of class OIDs */
64  OID cur_oid; /* Identifier of the current object */
65  RECDES in_recdes; /* Input record descriptor */
66  int n_attrs; /* Number of attribute ID's */
67  ATTR_ID *attr_ids; /* Specification of the attribute(s) to sort on */
68  int *attrs_prefix_length; /* prefix length */
70  HEAP_SCANCACHE hfscan_cache; /* A heap scan cache */
71  HEAP_CACHE_ATTRINFO attr_info; /* Attribute information */
72  int n_nulls; /* Number of NULLs */
73  int n_oids; /* Number of OIDs */
74  int n_classes; /* cardinality of the hfids, the class_ids, and (with n_attrs) the attr_ids arrays */
75  int cur_class; /* index into the hfids, class_ids, and attr_ids arrays */
78 
80 
83  const char *fk_name;
87 
89 };
90 
91 typedef struct btree_page BTREE_PAGE;
92 struct btree_page
93 {
97 };
98 
99 typedef struct load_args LOAD_ARGS;
100 struct load_args
101 { /* This structure is never written to disk; thus logical ordering of fields is ok. */
103  const char *bt_name; /* index name */
104 
105  RECDES *out_recdes; /* Pointer to current record descriptor collecting objects. */
106  RECDES leaf_nleaf_recdes; /* Record descriptor used for leaf and non-leaf records. */
107  RECDES ovf_recdes; /* Record descriptor used for overflow OID's records. */
108  char *new_pos; /* Current pointer in record being built. */
109  DB_VALUE current_key; /* Current key value */
110  int max_key_size; /* The maximum key size encountered so far; used for string types */
111  int cur_key_len; /* The length of the current key */
112 
113  /* Linked list variables */
116 
117  /* Variables for managing non-leaf, leaf & overflow pages */
119 
120 #if 0 /* TODO: currently not used */
121  VPID first_leafpgid;
122 #endif
123 
125 
127 
128  bool overflowing; /* Currently, are we filling in an overflow page (then, true); or a regular leaf page
129  * (then, false) */
130  int n_keys; /* Number of keys - note that in the context of MVCC, only keys that have at least one
131  * non-deleted object are counted. */
132 
133  int curr_non_del_obj_count; /* Number of objects that have not been deleted. Unique indexes must have only one such
134  * object. */
135  int curr_rec_max_obj_count; /* Maximum number of objects for current record. */
136  int curr_rec_obj_count; /* Current number of record objects. */
137 
138  PGSLOTID last_leaf_insert_slotid; /* Slotid of last inserted leaf record. */
139 
141 };
142 
144 
146 {
147  BTREE_SCAN bt_scan; /* Holds information regarding the scan of the current partition. */
148 
149  OID oid; /* Oid of current partition. */
150 
151  BTREE_NODE_HEADER *header; /* Header info for current partition */
152 
153  int key_cnt; /* Number of keys in current page in the current partition. */
154 
155  PAGE_PTR page; /* current page in the current partition. */
156 
157  PRUNING_CONTEXT pcontext; /* Pruning context for current partition. */
158 
159  BTID btid; /* BTID of the current partition. */
160 };
161 
162 // *INDENT-OFF*
164 {
165  public:
166  std::atomic_bool m_has_error;
167  std::atomic<std::uint64_t> m_tasks_executed;
171 
172  index_builder_loader_context () = default;
173 
174  protected:
175  void on_create (context_type &context) override;
176  void on_retire (context_type &context) override;
177  void on_recycle (context_type &context) override;
178 };
179 
181 {
182  private:
188  size_t m_memsize;
189 
190  std::atomic<int> &m_num_keys;
191  std::atomic<int> &m_num_oids;
192  std::atomic<int> &m_num_nulls;
193 
194  public:
196  {
199  BATCH_FULL
200  };
201 
202  index_builder_loader_task () = delete;
203 
204  index_builder_loader_task (const BTID *btid, const OID *class_oid, int unique_pk,
205  index_builder_loader_context &load_context, std::atomic<int> &num_keys,
206  std::atomic<int> &num_oids, std::atomic<int> &num_nulls);
208 
209  // add key to key set and return true if task is ready for execution, false otherwise
210  batch_key_status add_key (const DB_VALUE *key, const OID &oid);
211  bool has_keys () const;
212 
213  void execute (cubthread::entry &thread_ref);
214 
215  private:
216  void clear_keys ();
217 };
218 
219 // *INDENT-ON*
220 
221 
222 static int btree_save_last_leafrec (THREAD_ENTRY * thread_p, LOAD_ARGS * load_args);
223 static PAGE_PTR btree_connect_page (THREAD_ENTRY * thread_p, DB_VALUE * key, int max_key_len, VPID * pageid,
224  LOAD_ARGS * load_args, int node_level);
225 static int btree_build_nleafs (THREAD_ENTRY * thread_p, LOAD_ARGS * load_args, int n_nulls, int n_oids, int n_keys);
226 
227 static void btree_log_page (THREAD_ENTRY * thread_p, VFID * vfid, PAGE_PTR page_ptr);
228 static int btree_load_new_page (THREAD_ENTRY * thread_p, const BTID * btid, BTREE_NODE_HEADER * header, int node_level,
229  VPID * vpid_new, PAGE_PTR * page_new);
231 static int btree_first_oid (THREAD_ENTRY * thread_p, DB_VALUE * this_key, OID * class_oid, OID * first_oid,
232  MVCC_REC_HEADER * p_mvcc_rec_header, LOAD_ARGS * load_args);
233 static int btree_construct_leafs (THREAD_ENTRY * thread_p, const RECDES * in_recdes, void *arg);
234 static int btree_get_value_from_leaf_slot (THREAD_ENTRY * thread_p, BTID_INT * btid_int, PAGE_PTR leaf_ptr,
235  int slot_id, DB_VALUE * key, bool * clear_key);
236 #if defined(CUBRID_DEBUG)
237 static int btree_dump_sort_output (const RECDES * recdes, LOAD_ARGS * load_args);
238 #endif /* defined(CUBRID_DEBUG) */
239 static int btree_index_sort (THREAD_ENTRY * thread_p, SORT_ARGS * sort_args, SORT_PUT_FUNC * out_func, void *out_args);
240 static SORT_STATUS btree_sort_get_next (THREAD_ENTRY * thread_p, RECDES * temp_recdes, void *arg);
241 static int compare_driver (const void *first, const void *second, void *arg);
242 static int list_add (BTREE_NODE ** list, VPID * pageid);
243 static void list_remove_first (BTREE_NODE ** list);
244 static void list_clear (BTREE_NODE * list);
245 static int list_length (const BTREE_NODE * this_list);
246 #if defined(CUBRID_DEBUG)
247 static void list_print (const BTREE_NODE * this_list);
248 #endif /* defined(CUBRID_DEBUG) */
249 static int btree_pack_root_header (RECDES * Rec, BTREE_ROOT_HEADER * header, TP_DOMAIN * key_type);
250 static void btree_rv_save_root_head (int null_delta, int oid_delta, int key_delta, RECDES * recdes);
252  PAGE_PTR * pg_ptr, INT16 * slot_id, DB_VALUE * key,
253  bool * clear_key, bool is_desc, int *key_cnt,
254  BTREE_NODE_HEADER ** header, MVCC_SNAPSHOT * mvcc);
255 static int btree_load_check_fk (THREAD_ENTRY * thread_p, const LOAD_ARGS * load_args_local,
256  const SORT_ARGS * sort_args_local);
257 static int btree_is_slot_visible (THREAD_ENTRY * thread_p, BTID_INT * btid, PAGE_PTR pg_ptr,
258  MVCC_SNAPSHOT * mvcc_snapshot, int slot_id, bool * is_slot_visible);
259 
260 static int online_index_builder (THREAD_ENTRY * thread_p, BTID_INT * btid_int, HFID * hfids, OID * class_oids,
261  int n_classes, int *attrids, int n_attrs, FUNCTION_INDEX_INFO func_idx_info,
262  PRED_EXPR_WITH_CONTEXT * filter_pred, int *attrs_prefix_length,
265 static bool btree_is_worker_pool_logging_true ();
266 
267 /*
268  * btree_get_node_header () -
269  *
270  * return:
271  * page_ptr(in):
272  *
273  */
276 {
277  RECDES header_record;
278  BTREE_NODE_HEADER *header = NULL;
279 
280  assert (page_ptr != NULL);
281 
282 #if !defined(NDEBUG)
283  (void) pgbuf_check_page_ptype (thread_p, page_ptr, PAGE_BTREE);
284 #endif
285 
286  if (spage_get_record (thread_p, page_ptr, HEADER, &header_record, PEEK) != S_SUCCESS)
287  {
288  assert_release (false);
289  return NULL;
290  }
291 
292  header = (BTREE_NODE_HEADER *) header_record.data;
293  if (header != NULL)
294  {
295  assert (header->max_key_len >= 0);
296  }
297 
298  return header;
299 }
300 
301 /*
302  * btree_get_root_header () -
303  *
304  * return:
305  * page_ptr(in):
306  *
307  */
310 {
311  RECDES header_record;
312  BTREE_ROOT_HEADER *root_header = NULL;
313 
314  assert (page_ptr != NULL);
315 
316 #if !defined(NDEBUG)
317  (void) pgbuf_check_page_ptype (thread_p, page_ptr, PAGE_BTREE);
318 #endif
319 
320  if (spage_get_record (thread_p, page_ptr, HEADER, &header_record, PEEK) != S_SUCCESS)
321  {
322  assert_release (false);
323  return NULL;
324  }
325 
326  root_header = (BTREE_ROOT_HEADER *) header_record.data;
327  if (root_header != NULL)
328  {
329  assert (root_header->node.node_level > 0);
330  assert (root_header->node.max_key_len >= 0);
331  }
332 
333  return root_header;
334 }
335 
336 /*
337  * btree_get_overflow_header () -
338  *
339  * return:
340  * page_ptr(in):
341  *
342  */
345 {
346  RECDES header_record;
347 
348  assert (page_ptr != NULL);
349 
350 #if !defined(NDEBUG)
351  (void) pgbuf_check_page_ptype (thread_p, page_ptr, PAGE_BTREE);
352 #endif
353 
354  if (spage_get_record (thread_p, page_ptr, HEADER, &header_record, PEEK) != S_SUCCESS)
355  {
356  assert_release (false);
357  return NULL;
358  }
359 
360  return (BTREE_OVERFLOW_HEADER *) header_record.data;
361 }
362 
363 /*
364  * btree_init_node_header () - insert btree node header
365  *
366  * return:
367  * vfid(in):
368  * page_ptr(in):
369  * header(in):
370  *
371  */
372 int
373 btree_init_node_header (THREAD_ENTRY * thread_p, const VFID * vfid, PAGE_PTR page_ptr, BTREE_NODE_HEADER * header,
374  bool redo)
375 {
376  RECDES rec;
377  char rec_buf[IO_MAX_PAGE_SIZE + BTREE_MAX_ALIGN];
378 
379  assert (header != NULL);
380  assert (header->node_level > 0);
381  assert (header->max_key_len >= 0);
382 
383  /* create header record */
384  rec.area_size = DB_PAGESIZE;
385  rec.data = PTR_ALIGN (rec_buf, BTREE_MAX_ALIGN);
386  rec.type = REC_HOME;
387  rec.length = sizeof (BTREE_NODE_HEADER);
388  memcpy (rec.data, header, sizeof (BTREE_NODE_HEADER));
389 
390  if (redo == true)
391  {
392  /* log the new header record for redo purposes */
393  log_append_redo_data2 (thread_p, RVBT_NDHEADER_INS, vfid, page_ptr, HEADER, rec.length, rec.data);
394  }
395 
396  if (spage_insert_at (thread_p, page_ptr, HEADER, &rec) != SP_SUCCESS)
397  {
398  return ER_FAILED;
399  }
400 
401  return NO_ERROR;
402 }
403 
404 
405 /*
406  * btree_node_header_undo_log () -
407  *
408  * return:
409  * vfid(in):
410  * page_ptr(in):
411  *
412  */
413 int
415 {
416  RECDES rec;
417  if (spage_get_record (thread_p, page_ptr, HEADER, &rec, PEEK) != S_SUCCESS)
418  {
419  return ER_FAILED;
420  }
421 
422  log_append_undo_data2 (thread_p, RVBT_NDHEADER_UPD, vfid, page_ptr, HEADER, rec.length, rec.data);
423 
424  return NO_ERROR;
425 }
426 
427 /*
428  * btree_node_header_redo_log () -
429  *
430  * return:
431  * vfid(in):
432  * page_ptr(in):
433  *
434  */
435 int
437 {
438  RECDES rec;
439  if (spage_get_record (thread_p, page_ptr, HEADER, &rec, PEEK) != S_SUCCESS)
440  {
441  return ER_FAILED;
442  }
443 
444  log_append_redo_data2 (thread_p, RVBT_NDHEADER_UPD, vfid, page_ptr, HEADER, rec.length, rec.data);
445 
446  return NO_ERROR;
447 }
448 
449 /*
450  * btree_change_root_header_delta () -
451  *
452  * return:
453  * vfid(in):
454  * page_ptr(in):
455  * null_delta(in):
456  * oid_delta(in):
457  * key_delta(in):
458  *
459  */
460 int
461 btree_change_root_header_delta (THREAD_ENTRY * thread_p, VFID * vfid, PAGE_PTR page_ptr, int null_delta, int oid_delta,
462  int key_delta)
463 {
464  RECDES rec, delta_rec;
465  char delta_rec_buf[(3 * OR_INT_SIZE) + BTREE_MAX_ALIGN];
466  BTREE_ROOT_HEADER *root_header = NULL;
467 
468  delta_rec.data = NULL;
469  delta_rec.area_size = 3 * OR_INT_SIZE;
470  delta_rec.data = PTR_ALIGN (delta_rec_buf, BTREE_MAX_ALIGN);
471 
472  if (spage_get_record (thread_p, page_ptr, HEADER, &rec, PEEK) != S_SUCCESS)
473  {
474  return ER_FAILED;
475  }
476 
477  root_header = (BTREE_ROOT_HEADER *) rec.data;
478  root_header->num_nulls += null_delta;
479  root_header->num_oids += oid_delta;
480  root_header->num_keys += key_delta;
481 
482  /* save root head for undo purposes */
483  btree_rv_save_root_head (-null_delta, -oid_delta, -key_delta, &delta_rec);
484 
485  log_append_undoredo_data2 (thread_p, RVBT_ROOTHEADER_UPD, vfid, page_ptr, HEADER, delta_rec.length, rec.length,
486  delta_rec.data, rec.data);
487 
488  return NO_ERROR;
489 }
490 
491 
492 /*
493  * btree_pack_root_header () -
494  * return:
495  * rec(out):
496  * root_header(in):
497  *
498  * Note: Writes the first record (header record) for a root page.
499  * rec must be long enough to hold the header record.
500  */
501 static int
503 {
504  OR_BUF buf;
505  int rc = NO_ERROR;
506  int fixed_size = (int) offsetof (BTREE_ROOT_HEADER, packed_key_domain);
507 
508  memcpy (rec->data, root_header, fixed_size);
509 
510  or_init (&buf, rec->data + fixed_size, (rec->area_size == -1) ? -1 : (rec->area_size - fixed_size));
511 
512  rc = or_put_domain (&buf, key_type, 0, 0);
513 
514  rec->length = fixed_size + CAST_BUFLEN (buf.ptr - buf.buffer);
515  rec->type = REC_HOME;
516 
517  if (rc != NO_ERROR && er_errid () == NO_ERROR)
518  {
519  /* if an error occurs then set a generic error so that at least an error to be send to client. */
520  if (er_errid () == NO_ERROR)
521  {
522  assert (false);
524  }
525  }
526 
527  return rc;
528 }
529 
530 /*
531  * btree_init_root_header () - insert btree node header
532  *
533  * return:
534  * vfid(in):
535  * page_ptr(in):
536  * root_header(in):
537  *
538  */
539 int
540 btree_init_root_header (THREAD_ENTRY * thread_p, VFID * vfid, PAGE_PTR page_ptr, BTREE_ROOT_HEADER * root_header,
542 {
543  RECDES rec;
544  char copy_rec_buf[IO_MAX_PAGE_SIZE + BTREE_MAX_ALIGN];
545 
546  assert (root_header != NULL);
547  assert (root_header->node.node_level > 0);
548  assert (root_header->node.max_key_len >= 0);
549 
550  rec.area_size = DB_PAGESIZE;
551  rec.data = PTR_ALIGN (copy_rec_buf, BTREE_MAX_ALIGN);
552 
553  if (btree_pack_root_header (&rec, root_header, key_type) != NO_ERROR)
554  {
555  return ER_FAILED;
556  }
557 
558  /* insert the root header information into the root page */
559  if (spage_insert_at (thread_p, page_ptr, HEADER, &rec) != SP_SUCCESS)
560  {
561  return ER_FAILED;
562  }
563 
564  /* log the new header record for redo purposes */
565  log_append_redo_data2 (thread_p, RVBT_NDHEADER_INS, vfid, page_ptr, HEADER, rec.length, rec.data);
566 
567  return NO_ERROR;
568 }
569 
570 /*
571  * btree_init_overflow_header () - insert btree overflow node header
572  *
573  * return:
574  * page_ptr(in):
575  * ovf_header(in):
576  *
577  */
578 int
580 {
581  RECDES rec;
582  char copy_rec_buf[IO_MAX_PAGE_SIZE + BTREE_MAX_ALIGN];
583 
584  rec.area_size = DB_PAGESIZE;
585  rec.data = PTR_ALIGN (copy_rec_buf, BTREE_MAX_ALIGN);
586  memcpy (rec.data, ovf_header, sizeof (BTREE_OVERFLOW_HEADER));
587  rec.length = sizeof (BTREE_OVERFLOW_HEADER);
588  rec.type = REC_HOME;
589 
590  /* insert the root header information into the root page */
591  if (spage_insert_at (thread_p, page_ptr, HEADER, &rec) != SP_SUCCESS)
592  {
593  return ER_FAILED;
594  }
595 
596  return NO_ERROR;
597 }
598 
599 /*
600  * btree_rv_save_root_head () - Save root head stats FOR LOGICAL LOG PURPOSES
601  * return:
602  * null_delta(in):
603  * oid_delta(in):
604  * key_delta(in):
605  * recdes(out):
606  *
607  * Note: Copy the root header statistics to the data area provided.
608  *
609  * Note: This is a UTILITY routine, but not an actual recovery routine.
610  */
611 static void
612 btree_rv_save_root_head (int null_delta, int oid_delta, int key_delta, RECDES * recdes)
613 {
614  char *datap;
615 
616  assert (recdes->area_size >= 3 * OR_INT_SIZE);
617 
618  recdes->length = 0;
619  datap = (char *) recdes->data;
620  OR_PUT_INT (datap, null_delta);
621  datap += OR_INT_SIZE;
622  OR_PUT_INT (datap, oid_delta);
623  datap += OR_INT_SIZE;
624  OR_PUT_INT (datap, key_delta);
625  datap += OR_INT_SIZE;
626 
627  recdes->length = CAST_STRLEN (datap - recdes->data);
628 }
629 
630 /*
631  * btree_rv_mvcc_save_increments () - Save unique_stats
632  * return:
633  * btid(in):
634  * max_key_len(in):
635  * null_delta(in):
636  * oid_delta(in):
637  * key_delta(in):
638  * recdes(in):
639  *
640  * Note: Copy the unique statistics to the data area provided.
641  *
642  * Note: This is a UTILITY routine, but not an actual recovery routine.
643  */
644 void
645 btree_rv_mvcc_save_increments (const BTID * btid, int key_delta, int oid_delta, int null_delta, RECDES * recdes)
646 {
647  char *datap;
648 
649  assert (recdes != NULL && (recdes->area_size >= ((3 * OR_INT_SIZE) + OR_BTID_ALIGNED_SIZE)));
650 
651  recdes->length = (3 * OR_INT_SIZE) + OR_BTID_ALIGNED_SIZE;
652  datap = (char *) recdes->data;
653 
654  OR_PUT_BTID (datap, btid);
655  datap += OR_BTID_ALIGNED_SIZE;
656 
657  OR_PUT_INT (datap, key_delta);
658  datap += OR_INT_SIZE;
659 
660  OR_PUT_INT (datap, oid_delta);
661  datap += OR_INT_SIZE;
662 
663  OR_PUT_INT (datap, null_delta);
664  datap += OR_INT_SIZE;
665 
666  recdes->length = CAST_STRLEN (datap - recdes->data);
667 }
668 
669 /*
670  * btree_get_next_overflow_vpid () -
671  *
672  * return:
673  * page_ptr(in):
674  *
675  */
676 int
678 {
679  BTREE_OVERFLOW_HEADER *ovf_header = NULL;
680 
681  ovf_header = btree_get_overflow_header (thread_p, page_ptr);
682  if (ovf_header == NULL)
683  {
684  return ER_FAILED;
685  }
686 
687  *vpid = ovf_header->next_vpid;
688 
689  return NO_ERROR;
690 }
691 
692 /*
693  * xbtree_load_index () - create & load b+tree index
694  * return: BTID * (btid on success and NULL on failure)
695  * btid is set as a side effect.
696  * btid(out):
697  * btid: Set to the created B+tree index identifier
698  * (Note: btid->vfid.volid should be set by the caller)
699  * bt_name(in): index name
700  * key_type(in): Key type corresponding to the attribute.
701  * class_oids(in): OID of the class for which the index will be created
702  * n_classes(in):
703  * n_attrs(in):
704  * attr_ids(in): Identifier of the attribute of the class for which the index
705  * will be created.
706  * hfids(in): Identifier of the heap file containing the instances of the
707  * class
708  * unique_pk(in):
709  * not_null_flag(in):
710  * fk_refcls_oid(in):
711  * fk_refcls_pk_btid(in):
712  * fk_name(in):
713  *
714  */
715 BTID *
716 xbtree_load_index (THREAD_ENTRY * thread_p, BTID * btid, const char *bt_name, TP_DOMAIN * key_type, OID * class_oids,
717  int n_classes, int n_attrs, int *attr_ids, int *attrs_prefix_length, HFID * hfids, int unique_pk,
719  char *pred_stream, int pred_stream_size, char *func_pred_stream, int func_pred_stream_size,
720  int func_col_id, int func_attr_index_start)
721 {
722  LOG_TDES *tdes = NULL;
723  SORT_ARGS sort_args_info, *sort_args;
724  LOAD_ARGS load_args_info, *load_args;
725  int cur_class, attr_offset;
726  VPID root_vpid;
728  PRED_EXPR_WITH_CONTEXT *filter_pred = NULL;
730  DB_TYPE single_node_type = DB_TYPE_NULL;
731  XASL_UNPACK_INFO *func_unpack_info = NULL;
732  bool has_fk;
733  BTID btid_global_stats = BTID_INITIALIZER;
734  OID *notification_class_oid;
735  bool is_sysop_started = false;
736 
737  /* Check for robustness */
738  if (!btid || !hfids || !class_oids || !attr_ids || !key_type)
739  {
741  return NULL;
742  }
743 
744  sort_args = &sort_args_info;
745  load_args = &load_args_info;
746 
747  /* Initialize pointers which might be used in case of error */
748  load_args->nleaf.pgptr = NULL;
749  load_args->leaf.pgptr = NULL;
750  load_args->ovf.pgptr = NULL;
751  load_args->leaf_nleaf_recdes.data = NULL;
752  load_args->ovf_recdes.data = NULL;
753  load_args->out_recdes = NULL;
754  load_args->push_list = NULL;
755  load_args->pop_list = NULL;
756 
757  /*
758  * Start a TOP SYSTEM OPERATION.
759  * This top system operation will be either ABORTED (case of failure) or
760  * COMMITTED, so that the new file becomes kind of permanent. This allows
761  * us to make use of un-used pages in the case of a bad init_pgcnt guess.
762  */
763 
764  log_sysop_start (thread_p);
765  is_sysop_started = true;
766 
767  thread_p->push_resource_tracks ();
768 
769  btid_int.sys_btid = btid;
770  btid_int.unique_pk = unique_pk;
771 #if !defined(NDEBUG)
772  if (unique_pk)
773  {
774  assert (BTREE_IS_UNIQUE (btid_int.unique_pk));
776  }
777 #endif
778  btid_int.key_type = key_type;
779  VFID_SET_NULL (&btid_int.ovfid);
781  COPY_OID (&btid_int.topclass_oid, &class_oids[0]);
782 
783  /*
784  * for btree_range_search, part_key_desc is re-set at btree_initialize_bts
785  */
786  btid_int.part_key_desc = 0;
787 
788  /* init index key copy_buf info */
789  btid_int.copy_buf = NULL;
790  btid_int.copy_buf_len = 0;
791 
792  btid_int.nonleaf_key_type = btree_generate_prefix_domain (&btid_int);
793 
794  /* Initialize the fields of sorting argument structures */
796  sort_args->unique_pk = unique_pk;
797  sort_args->not_null_flag = not_null_flag;
798  sort_args->hfids = hfids;
799  sort_args->class_ids = class_oids;
800  sort_args->attr_ids = attr_ids;
801  sort_args->n_attrs = n_attrs;
803  sort_args->n_classes = n_classes;
804  sort_args->key_type = key_type;
805  OID_SET_NULL (&sort_args->cur_oid);
806  sort_args->n_nulls = 0;
807  sort_args->n_oids = 0;
808  sort_args->cur_class = 0;
809  sort_args->scancache_inited = 0;
810  sort_args->attrinfo_inited = 0;
811  sort_args->btid = &btid_int;
812  sort_args->fk_refcls_oid = fk_refcls_oid;
814  sort_args->fk_name = fk_name;
815  if (pred_stream && pred_stream_size > 0)
816  {
817  if (stx_map_stream_to_filter_pred (thread_p, &filter_pred, pred_stream, pred_stream_size) != NO_ERROR)
818  {
819  goto error;
820  }
821  }
822  sort_args->filter = filter_pred;
823  sort_args->filter_eval_func = (filter_pred) ? eval_fnc (thread_p, filter_pred->pred, &single_node_type) : NULL;
824  sort_args->func_index_info = NULL;
825  if (func_pred_stream && func_pred_stream_size > 0)
826  {
827  func_index_info.expr_stream = func_pred_stream;
828  func_index_info.expr_stream_size = func_pred_stream_size;
829  func_index_info.col_id = func_col_id;
830  func_index_info.attr_index_start = func_attr_index_start;
831  func_index_info.expr = NULL;
832  if (stx_map_stream_to_func_pred (thread_p, &func_index_info.expr, func_pred_stream,
833  func_pred_stream_size, &func_unpack_info))
834  {
835  goto error;
836  }
837  sort_args->func_index_info = &func_index_info;
838  }
839 
840  /*
841  * Start a heap scan cache for reading objects using the first nun-null heap
842  * We are guaranteed that such a heap exists, otherwise btree_load_index
843  * would not have been called.
844  */
845  while (sort_args->cur_class < sort_args->n_classes && HFID_IS_NULL (&sort_args->hfids[sort_args->cur_class]))
846  {
847  sort_args->cur_class++;
848  }
849 
850  cur_class = sort_args->cur_class;
851  attr_offset = cur_class * sort_args->n_attrs;
852 
853  /* Start scancache */
854  has_fk = (fk_refcls_oid != NULL && !OID_ISNULL (fk_refcls_oid));
855  if (heap_scancache_start (thread_p, &sort_args->hfscan_cache, &sort_args->hfids[cur_class],
856  &sort_args->class_ids[cur_class], !has_fk, false, NULL) != NO_ERROR)
857  {
858  goto error;
859  }
860  sort_args->scancache_inited = 1;
861 
862  /* After building index acquire lock on table, the transaction has deadlock priority */
863  tdes = LOG_FIND_CURRENT_TDES (thread_p);
864  if (tdes)
865  {
866  tdes->has_deadlock_priority = true;
867  }
868 
869  if (heap_attrinfo_start (thread_p, &sort_args->class_ids[cur_class], sort_args->n_attrs,
870  &sort_args->attr_ids[attr_offset], &sort_args->attr_info) != NO_ERROR)
871  {
872  goto error;
873  }
874  if (sort_args->filter)
875  {
876  if (heap_attrinfo_start (thread_p, &sort_args->class_ids[cur_class], sort_args->filter->num_attrs_pred,
877  sort_args->filter->attrids_pred, sort_args->filter->cache_pred) != NO_ERROR)
878  {
879  goto error;
880  }
881  }
882  if (sort_args->func_index_info)
883  {
884  if (heap_attrinfo_start (thread_p, &sort_args->class_ids[cur_class], sort_args->n_attrs,
885  &sort_args->attr_ids[attr_offset],
886  sort_args->func_index_info->expr->cache_attrinfo) != NO_ERROR)
887  {
888  goto error;
889  }
890  }
891  sort_args->attrinfo_inited = 1;
892 
893  if (btree_create_file (thread_p, &class_oids[0], attr_ids[0], btid) != NO_ERROR)
894  {
895  ASSERT_ERROR ();
896  goto error;
897  }
898  btree_get_root_vpid_from_btid (thread_p, btid, &root_vpid);
899 
900  /* if loading is aborted or if transaction is aborted, vacuum must be notified before file is destoyed. */
902 
904  load_args->btid = &btid_int;
905  load_args->bt_name = bt_name;
906  db_make_null (&load_args->current_key);
907  VPID_SET_NULL (&load_args->nleaf.vpid);
908  load_args->nleaf.pgptr = NULL;
909  VPID_SET_NULL (&load_args->leaf.vpid);
910  load_args->leaf.pgptr = NULL;
911  VPID_SET_NULL (&load_args->ovf.vpid);
912  load_args->ovf.pgptr = NULL;
913  load_args->n_keys = 0;
914  load_args->curr_non_del_obj_count = 0;
915 
917  load_args->leaf_nleaf_recdes.length = 0;
918  load_args->leaf_nleaf_recdes.type = REC_HOME;
919  load_args->leaf_nleaf_recdes.data = (char *) os_malloc (load_args->leaf_nleaf_recdes.area_size);
920  if (load_args->leaf_nleaf_recdes.data == NULL)
921  {
923  goto error;
924  }
925  load_args->ovf_recdes.area_size = DB_PAGESIZE;
926  load_args->ovf_recdes.length = 0;
927  load_args->ovf_recdes.type = REC_HOME;
928  load_args->ovf_recdes.data = (char *) os_malloc (load_args->ovf_recdes.area_size);
929  if (load_args->ovf_recdes.data == NULL)
930  {
932  goto error;
933  }
934  load_args->out_recdes = NULL;
935 
936  /* Allocate a root page and save the page_id */
937  *load_args->btid->sys_btid = *btid;
938  btid_global_stats = *btid;
939 
941  {
942  _er_log_debug (ARG_FILE_LINE, "DEBUG_BTREE: load start on class(%d, %d, %d), btid(%d, (%d, %d)).",
943  sort_args->class_ids[sort_args->cur_class].volid,
944  sort_args->class_ids[sort_args->cur_class].pageid,
945  sort_args->class_ids[sort_args->cur_class].slotid, sort_args->btid->sys_btid->root_pageid,
946  sort_args->btid->sys_btid->vfid.volid, sort_args->btid->sys_btid->vfid.fileid);
947  }
948 
949  /* Build the leaf pages of the btree as the output of the sort. We do not estimate the number of pages required. */
950  if (btree_index_sort (thread_p, sort_args, btree_construct_leafs, load_args) != NO_ERROR)
951  {
952  goto error;
953  }
954 
956  {
958  "DEBUG_BTREE: load finished all. %d classes loaded, found %d nulls and %d oids, "
959  "load %d keys.", sort_args->n_classes, sort_args->n_nulls, sort_args->n_oids, load_args->n_keys);
960  }
961 
962  if (sort_args->attrinfo_inited)
963  {
964  heap_attrinfo_end (thread_p, &sort_args->attr_info);
965  if (sort_args->filter)
966  {
967  heap_attrinfo_end (thread_p, sort_args->filter->cache_pred);
968  }
969  if (sort_args->func_index_info)
970  {
971  heap_attrinfo_end (thread_p, sort_args->func_index_info->expr->cache_attrinfo);
972  }
973  }
974  sort_args->attrinfo_inited = 0;
975  if (sort_args->scancache_inited)
976  {
977  (void) heap_scancache_end (thread_p, &sort_args->hfscan_cache);
978  }
979  sort_args->scancache_inited = 0;
980 
981  /* Just to make sure that there were entries to put into the tree */
982  if (load_args->leaf.pgptr != NULL)
983  {
984  /* Save the last leaf record */
985 
986  if (btree_save_last_leafrec (thread_p, load_args) != NO_ERROR)
987  {
989  goto error;
990  }
991 
992  /* No need to deal with overflow pages anymore */
993  load_args->ovf.pgptr = NULL;
994 
995  /* Check the correctness of the foreign key, if any. */
996  if (has_fk)
997  {
998  if (btree_load_check_fk (thread_p, load_args, sort_args) != NO_ERROR)
999  {
1000  goto error;
1001  }
1002  }
1003 
1004  /* Build the non leaf nodes of the btree; Root page id will be assigned here */
1005 
1006  if (btree_build_nleafs (thread_p, load_args, sort_args->n_nulls, sort_args->n_oids, load_args->n_keys) !=
1007  NO_ERROR)
1008  {
1010  goto error;
1011  }
1012 
1013  /* There is at least one leaf page */
1014 
1015  /* Release the memory area */
1017  os_free_and_init (load_args->ovf_recdes.data);
1018  pr_clear_value (&load_args->current_key);
1019 
1021  {
1022  _er_log_debug (ARG_FILE_LINE, "DEBUG_BTREE: load built index btid (%d, (%d, %d)).",
1023  btid_int.sys_btid->root_pageid, btid_int.sys_btid->vfid.volid, btid_int.sys_btid->vfid.fileid);
1024  }
1025 
1026 #if !defined(NDEBUG)
1027  (void) btree_verify_tree (thread_p, &class_oids[0], &btid_int, bt_name);
1028 #endif
1029  }
1030  else
1031  {
1033  {
1034  _er_log_debug (ARG_FILE_LINE, "DEBUG_BTREE: load didn't build any leaves btid (%d, (%d, %d)).",
1035  btid_int.sys_btid->root_pageid, btid_int.sys_btid->vfid.volid, btid_int.sys_btid->vfid.fileid);
1036  }
1037  /* redo an empty index, but first destroy the one we created. the safest way is to abort changes so far. */
1038  log_sysop_abort (thread_p);
1039  is_sysop_started = false;
1040 
1042  os_free_and_init (load_args->ovf_recdes.data);
1043  pr_clear_value (&load_args->current_key);
1044 
1045  BTID_SET_NULL (btid);
1046  if (xbtree_add_index (thread_p, btid, key_type, &class_oids[0], attr_ids[0], unique_pk, sort_args->n_oids,
1047  sort_args->n_nulls, load_args->n_keys) == NULL)
1048  {
1049  goto error;
1050  }
1051  }
1052 
1053  if (!VFID_ISNULL (&load_args->btid->ovfid))
1054  {
1055  /* notification */
1056  if (!OID_ISNULL (&class_oids[0]))
1057  {
1058  notification_class_oid = &class_oids[0];
1059  }
1060  else
1061  {
1062  notification_class_oid = &btid_int.topclass_oid;
1063  }
1064  BTREE_SET_CREATED_OVERFLOW_KEY_NOTIFICATION (thread_p, NULL, NULL, notification_class_oid, btid, bt_name);
1065  }
1066 
1067  if (sort_args->filter)
1068  {
1069  /* to clear db values from dbvalue regu variable */
1070  qexec_clear_pred_context (thread_p, sort_args->filter, true);
1071  }
1072  if (filter_pred != NULL)
1073  {
1074  if (filter_pred->unpack_info != NULL)
1075  {
1076  free_xasl_unpack_info (thread_p, filter_pred->unpack_info);
1077  }
1078  db_private_free_and_init (thread_p, filter_pred);
1079  }
1080  if (sort_args->func_index_info && sort_args->func_index_info->expr)
1081  {
1082  (void) qexec_clear_func_pred (thread_p, sort_args->func_index_info->expr);
1083  }
1084  if (func_unpack_info)
1085  {
1086  free_xasl_unpack_info (thread_p, func_unpack_info);
1087  }
1088 
1089  thread_p->pop_resource_tracks ();
1090 
1091  if (is_sysop_started)
1092  {
1093  /* todo: we have the option to commit & undo here. on undo, we can destroy the file directly. */
1094  log_sysop_attach_to_outer (thread_p);
1095  if (unique_pk)
1096  {
1097  /* drop statistics if aborted */
1099  }
1100  }
1101  else
1102  {
1103  /* index was not loaded and xbtree_add_index was called instead. we have nothing to log here. */
1104  }
1105 
1106  logpb_force_flush_pages (thread_p);
1107 
1109  {
1110  _er_log_debug (ARG_FILE_LINE, "BTREE_DEBUG: load finished successful index btid(%d, (%d, %d)).",
1111  btid_int.sys_btid->root_pageid, btid_int.sys_btid->vfid.volid, btid_int.sys_btid->vfid.fileid);
1112  }
1113 
1114  return btid;
1115 
1116 error:
1117 
1119  {
1120  _er_log_debug (ARG_FILE_LINE, "BTREE_DEBUG: load aborted index btid(%d, (%d, %d)).",
1121  btid_int.sys_btid->root_pageid, btid_int.sys_btid->vfid.volid, btid_int.sys_btid->vfid.fileid);
1122  }
1123 
1124  if (!BTID_IS_NULL (&btid_global_stats))
1125  {
1126  logtb_delete_global_unique_stats (thread_p, &btid_global_stats);
1127  }
1128 
1129  if (sort_args->scancache_inited)
1130  {
1131  (void) heap_scancache_end (thread_p, &sort_args->hfscan_cache);
1132  }
1133  if (sort_args->attrinfo_inited)
1134  {
1135  heap_attrinfo_end (thread_p, &sort_args->attr_info);
1136  if (sort_args->filter)
1137  {
1138  heap_attrinfo_end (thread_p, sort_args->filter->cache_pred);
1139  }
1140  if (sort_args->func_index_info && sort_args->func_index_info->expr)
1141  {
1142  heap_attrinfo_end (thread_p, sort_args->func_index_info->expr->cache_attrinfo);
1143  }
1144  }
1145  VFID_SET_NULL (&btid->vfid);
1146  btid->root_pageid = NULL_PAGEID;
1147  if (load_args->leaf_nleaf_recdes.data)
1148  {
1150  }
1151  if (load_args->ovf_recdes.data)
1152  {
1153  os_free_and_init (load_args->ovf_recdes.data);
1154  }
1155  pr_clear_value (&load_args->current_key);
1156 
1157  if (load_args->leaf.pgptr)
1158  {
1159  pgbuf_unfix_and_init (thread_p, load_args->leaf.pgptr);
1160  }
1161  if (load_args->ovf.pgptr)
1162  {
1163  pgbuf_unfix_and_init (thread_p, load_args->ovf.pgptr);
1164  }
1165  if (load_args->nleaf.pgptr)
1166  {
1167  pgbuf_unfix_and_init (thread_p, load_args->nleaf.pgptr);
1168  }
1169  if (load_args->push_list != NULL)
1170  {
1171  list_clear (load_args->push_list);
1172  load_args->push_list = NULL;
1173  }
1174  if (load_args->pop_list != NULL)
1175  {
1176  list_clear (load_args->pop_list);
1177  load_args->pop_list = NULL;
1178  }
1179 
1180  if (sort_args->filter)
1181  {
1182  /* to clear db values from dbvalue regu variable */
1183  qexec_clear_pred_context (thread_p, sort_args->filter, true);
1184  }
1185  if (filter_pred != NULL)
1186  {
1187  if (filter_pred->unpack_info != NULL)
1188  {
1189  free_xasl_unpack_info (thread_p, filter_pred->unpack_info);
1190  }
1191  db_private_free_and_init (thread_p, filter_pred);
1192  }
1193  if (sort_args->func_index_info && sort_args->func_index_info->expr)
1194  {
1195  (void) qexec_clear_func_pred (thread_p, sort_args->func_index_info->expr);
1196  }
1197  if (func_unpack_info)
1198  {
1199  free_xasl_unpack_info (thread_p, func_unpack_info);
1200  }
1201 
1202  thread_p->pop_resource_tracks ();
1203 
1204  if (is_sysop_started)
1205  {
1206  log_sysop_abort (thread_p);
1207  }
1208 
1209  return NULL;
1210 }
1211 
1212 /*
1213  * btree_save_last_leafrec () - save the last leaf record
1214  * return: NO_ERROR
1215  * load_args(in): Collection of info. for btree load operation
1216  *
1217  * Note: Stores the last leaf record left in the load_args->out_recdes
1218  * area to the last leaf page (or to the last overflow page).
1219  * Then it saves the last leaf page (and the last overflow page,
1220  * if there is one) to the disk.
1221  */
1222 static int
1224 {
1225  INT16 slotid;
1226  int sp_success;
1227  int cur_maxspace;
1228  int ret = NO_ERROR;
1229  BTREE_NODE_HEADER *header = NULL;
1230 
1231  if (load_args->overflowing == true)
1232  {
1233  /* Store the record in current overflow page */
1234  sp_success = spage_insert (thread_p, load_args->ovf.pgptr, &load_args->ovf_recdes, &slotid);
1235  if (sp_success != SP_SUCCESS)
1236  {
1237  goto exit_on_error;
1238  }
1239 
1240  assert (slotid > 0);
1241 
1242  /* Save the current overflow page */
1243  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->ovf.pgptr);
1244  load_args->ovf.pgptr = NULL;
1245  }
1246 
1247  /* Insert leaf record too */
1248  cur_maxspace = spage_max_space_for_new_record (thread_p, load_args->leaf.pgptr);
1249  if (((cur_maxspace - load_args->leaf_nleaf_recdes.length) < LOAD_FIXED_EMPTY_FOR_LEAF)
1250  && (spage_number_of_records (load_args->leaf.pgptr) > 1))
1251  {
1252  /* New record does not fit into the current leaf page (within the threshold value); so allocate a new leaf page
1253  * and dump the current leaf page. */
1254  if (btree_proceed_leaf (thread_p, load_args) == NULL)
1255  {
1256  goto exit_on_error;
1257  }
1258  }
1259 
1260  /* Insert the record to the current leaf page */
1261  sp_success = spage_insert (thread_p, load_args->leaf.pgptr, &load_args->leaf_nleaf_recdes, &slotid);
1262  if (sp_success != SP_SUCCESS)
1263  {
1264  goto exit_on_error;
1265  }
1266 
1267  assert (slotid > 0);
1268 
1269  /* Update the node header information for this record */
1270  if (load_args->cur_key_len >= BTREE_MAX_KEYLEN_INPAGE)
1271  {
1272  if (load_args->leaf.hdr.max_key_len < DISK_VPID_SIZE)
1273  {
1274  load_args->leaf.hdr.max_key_len = DISK_VPID_SIZE;
1275  }
1276  }
1277  else
1278  {
1279  if (load_args->leaf.hdr.max_key_len < load_args->cur_key_len)
1280  {
1281  load_args->leaf.hdr.max_key_len = load_args->cur_key_len;
1282  }
1283  }
1284 
1285  /* Update the leaf header of the current leaf page */
1286  header = btree_get_node_header (thread_p, load_args->leaf.pgptr);
1287  if (header == NULL)
1288  {
1289  goto exit_on_error;
1290  }
1291 
1292  *header = load_args->leaf.hdr;
1293 
1294  /* Save the current leaf page */
1295  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->leaf.pgptr);
1296  load_args->leaf.pgptr = NULL;
1297 
1298  return ret;
1299 
1300 exit_on_error:
1301 
1302  if (load_args->leaf.pgptr)
1303  {
1304  pgbuf_unfix_and_init (thread_p, load_args->leaf.pgptr);
1305  }
1306  if (load_args->ovf.pgptr)
1307  {
1308  pgbuf_unfix_and_init (thread_p, load_args->ovf.pgptr);
1309  }
1310 
1311  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
1312 }
1313 
1314 /*
1315  * btree_connect_page () - Connect child page to the new parent page
1316  * return: PAGE_PTR (pointer to the parent page if finished successfully,
1317  * or NULL in case of an error)
1318  * key(in): Biggest key value (or, separator value in case of string
1319  * keys) of the child page to be connected.
1320  * max_key_len(in): size of the biggest key in this leaf page
1321  * pageid(in): identifier of this leaf page
1322  * load_args(in):
1323  *
1324  * Note: This function connects a page to its parent page. In the
1325  * parent level a new record is prepared with the given & pageid
1326  * parameters and inserted into current non-leaf page being
1327  * filled up. If the record does not fit into this page within
1328  * the given threshold boundaries (LOAD_FIXED_EMPTY_FOR_NONLEAF bytes of each
1329  * page are reserved for future insertions) then this page is
1330  * flushed to disk and a new page is allocated to become the
1331  * current non-leaf page.
1332  */
1333 
1334 static PAGE_PTR
1335 btree_connect_page (THREAD_ENTRY * thread_p, DB_VALUE * key, int max_key_len, VPID * pageid, LOAD_ARGS * load_args,
1336  int node_level)
1337 {
1338  NON_LEAF_REC nleaf_rec;
1339  INT16 slotid;
1340  int sp_success;
1341  int cur_maxspace;
1342  int key_len;
1343  int key_type = BTREE_NORMAL_KEY;
1344  BTREE_NODE_HEADER *header = NULL;
1345 
1346  /* form the leaf record (create the header & insert the key) */
1347  cur_maxspace = spage_max_space_for_new_record (thread_p, load_args->nleaf.pgptr);
1348 
1349  nleaf_rec.pnt = *pageid;
1350  key_len = btree_get_disk_size_of_key (key);
1351  if (key_len < BTREE_MAX_KEYLEN_INPAGE)
1352  {
1353  nleaf_rec.key_len = key_len;
1354  key_type = BTREE_NORMAL_KEY;
1355  }
1356  else
1357  {
1358  nleaf_rec.key_len = -1;
1359  key_type = BTREE_OVERFLOW_KEY;
1360 
1361  if (VFID_ISNULL (&load_args->btid->ovfid))
1362  {
1363  if (btree_create_overflow_key_file (thread_p, load_args->btid) != NO_ERROR)
1364  {
1365  return NULL;
1366  }
1367  }
1368  }
1369 
1370  if (btree_write_record (thread_p, load_args->btid, &nleaf_rec, key, BTREE_NON_LEAF_NODE, key_type, key_len, true,
1371  NULL, NULL, NULL, &load_args->leaf_nleaf_recdes) != NO_ERROR)
1372  {
1373  return NULL;
1374  }
1375 
1376  if ((cur_maxspace - load_args->leaf_nleaf_recdes.length) < LOAD_FIXED_EMPTY_FOR_NONLEAF)
1377  {
1378 
1379  /* New record does not fit into the current non-leaf page (within the threshold value); so allocate a new
1380  * non-leaf page and dump the current non-leaf page. */
1381 
1382  /* Update the non-leaf page header */
1383  header = btree_get_node_header (thread_p, load_args->nleaf.pgptr);
1384  if (header == NULL)
1385  {
1386  return NULL;
1387  }
1388 
1389  *header = load_args->nleaf.hdr;
1390 
1391  /* Flush the current non-leaf page */
1392  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->nleaf.pgptr);
1393  load_args->nleaf.pgptr = NULL;
1394 
1395  /* Insert the pageid to the linked list */
1396  if (list_add (&load_args->push_list, &load_args->nleaf.vpid) != NO_ERROR)
1397  {
1398  return NULL;
1399  }
1400 
1401  /* get a new non-leaf page */
1402  if (btree_load_new_page (thread_p, load_args->btid->sys_btid, &load_args->nleaf.hdr, node_level,
1403  &load_args->nleaf.vpid, &load_args->nleaf.pgptr) != NO_ERROR)
1404  {
1405  ASSERT_ERROR ();
1406  return NULL;
1407  }
1408  if (load_args->nleaf.pgptr == NULL)
1409  {
1410  assert_release (false);
1411  return NULL;
1412  }
1413  } /* get a new leaf */
1414 
1415  /* Insert the record to the current leaf page */
1416  sp_success = spage_insert (thread_p, load_args->nleaf.pgptr, &load_args->leaf_nleaf_recdes, &slotid);
1417  if (sp_success != SP_SUCCESS)
1418  {
1419  return NULL;
1420  }
1421 
1422  assert (slotid > 0);
1423 
1424  /* Update the node header information for this record */
1425  if (load_args->nleaf.hdr.max_key_len < max_key_len)
1426  {
1427  load_args->nleaf.hdr.max_key_len = max_key_len;
1428  }
1429 
1430  return load_args->nleaf.pgptr;
1431 }
1432 
1433 /*
1434  * btree_build_nleafs () -
1435  * return: NO_ERROR
1436  * load_args(in): Collection of information on how to build B+tree.
1437  * n_nulls(in):
1438  * n_oids(in):
1439  * n_keys(in):
1440  *
1441  * Note: This function builds the non-leaf level nodes of the B+Tree
1442  * index in three phases. In the first phase, the first non-leaf
1443  * level nodes of the tree are constructed. Then, the upper
1444  * levels are built on top of this level, and finally, the last
1445  * non-leaf page (the single page of the top level) is updated
1446  * to become the root page.
1447  */
1448 static int
1449 btree_build_nleafs (THREAD_ENTRY * thread_p, LOAD_ARGS * load_args, int n_nulls, int n_oids, int n_keys)
1450 {
1451  RECDES temp_recdes; /* Temporary record descriptor; */
1452  char *temp_data = NULL;
1453  VPID next_vpid;
1454  PAGE_PTR next_pageptr = NULL;
1455 
1456  /* Variables used in the second phase to go over lower level non-leaf pages */
1457  VPID cur_nleafpgid;
1458  PAGE_PTR cur_nleafpgptr = NULL;
1459 
1460  BTREE_NODE *temp;
1461  BTREE_ROOT_HEADER root_header_info, *root_header = NULL;
1462  BTREE_NODE_HEADER *header = NULL;
1463  int key_cnt;
1464  int max_key_len, new_max;
1465  LEAF_REC leaf_pnt;
1466  NON_LEAF_REC nleaf_pnt;
1467  /* Variables for keeping keys */
1468  DB_VALUE prefix_key; /* Prefix key; prefix of last & first keys; used only if type is one of the string
1469  * types */
1470  int last_key_offset, first_key_offset;
1471  bool clear_last_key = false, clear_first_key = false;
1472 
1473  int ret = NO_ERROR;
1474  int node_level = 2; /* leaf level = 1, lowest non-leaf level = 2 */
1475  RECDES rec;
1476  char rec_buf[IO_MAX_PAGE_SIZE + BTREE_MAX_ALIGN];
1477  DB_VALUE last_key; /* Last key of the current page */
1478  DB_VALUE first_key; /* First key of the next page; used only if key_type is one of the string types */
1479 
1480  root_header = &root_header_info;
1481 
1482  rec.area_size = DB_PAGESIZE;
1483  rec.data = PTR_ALIGN (rec_buf, BTREE_MAX_ALIGN);
1484 
1485  btree_init_temp_key_value (&clear_last_key, &last_key);
1486  btree_init_temp_key_value (&clear_first_key, &first_key);
1487  db_make_null (&prefix_key);
1488 
1489  temp_data = (char *) os_malloc (DB_PAGESIZE);
1490  if (temp_data == NULL)
1491  {
1494  goto end;
1495  }
1496 
1497  /*****************************************************
1498  PHASE I : Build the first non_leaf level nodes
1499  ****************************************************/
1500 
1501  assert (node_level == 2);
1502 
1503  /* Initialize the first non-leaf page */
1504  ret =
1505  btree_load_new_page (thread_p, load_args->btid->sys_btid, &load_args->nleaf.hdr, node_level, &load_args->nleaf.vpid,
1506  &load_args->nleaf.pgptr);
1507  if (ret != NO_ERROR)
1508  {
1509  ASSERT_ERROR ();
1510  goto end;
1511  }
1512  if (load_args->nleaf.pgptr == NULL)
1513  {
1514  assert_release (false);
1515  ret = ER_FAILED;
1516  goto end;
1517  }
1518 
1519  load_args->push_list = NULL;
1520  load_args->pop_list = NULL;
1521 
1522  db_make_null (&last_key);
1523 
1524  /* While there are some leaf pages do */
1525  load_args->leaf.vpid = load_args->vpid_first_leaf;
1526  while (!VPID_ISNULL (&(load_args->leaf.vpid)))
1527  {
1528  load_args->leaf.pgptr =
1530  if (load_args->leaf.pgptr == NULL)
1531  {
1532  ASSERT_ERROR_AND_SET (ret);
1533  goto end;
1534  }
1535 
1536  (void) pgbuf_check_page_ptype (thread_p, load_args->leaf.pgptr, PAGE_BTREE);
1537 
1538  key_cnt = btree_node_number_of_keys (thread_p, load_args->leaf.pgptr);
1539  assert (key_cnt > 0);
1540 
1541  /* obtain the header information for the leaf page */
1542  header = btree_get_node_header (thread_p, load_args->leaf.pgptr);
1543  if (header == NULL)
1544  {
1545  assert_release (false);
1546  ret = ER_FAILED;
1547  goto end;
1548  }
1549 
1550  /* get the maximum key length on this leaf page */
1551  max_key_len = header->max_key_len;
1552  next_vpid = header->next_vpid;
1553 
1554  /* set level 2 to first non-leaf page */
1555  load_args->nleaf.hdr.node_level = node_level;
1556 
1557  /* Learn the first key of the leaf page */
1558  if (spage_get_record (thread_p, load_args->leaf.pgptr, 1, &temp_recdes, PEEK) != S_SUCCESS)
1559 
1560  {
1561  assert_release (false);
1562  ret = ER_FAILED;
1563  goto end;
1564  }
1565 
1566  ret =
1567  btree_read_record (thread_p, load_args->btid, load_args->leaf.pgptr, &temp_recdes, &first_key, &leaf_pnt,
1568  BTREE_LEAF_NODE, &clear_first_key, &first_key_offset, PEEK_KEY_VALUE, NULL);
1569  if (ret != NO_ERROR)
1570  {
1571  ASSERT_ERROR ();
1572  goto end;
1573  }
1574 
1575  if (pr_is_prefix_key_type (TP_DOMAIN_TYPE (load_args->btid->key_type)))
1576  {
1577  /*
1578  * Key type is string or midxkey.
1579  * Should insert the prefix key to the parent level
1580  */
1581  if (DB_IS_NULL (&last_key))
1582  {
1583  /* is the first leaf When the types of leaf node are char, nchar, bit, the type that is saved on non-leaf
1584  * node is different. non-leaf spec (char -> varchar, nchar -> varnchar, bit -> varbit) hence it should
1585  * be configured by using setval of nonleaf_key_type. */
1586  ret = load_args->btid->nonleaf_key_type->type->setval (&prefix_key, &first_key, true);
1587  if (ret != NO_ERROR)
1588  {
1589  assert (!"setval error");
1590  goto end;
1591  }
1592  }
1593  else
1594  {
1595  /* Insert the prefix key to the parent level */
1596  ret = btree_get_prefix_separator (&last_key, &first_key, &prefix_key, load_args->btid->key_type);
1597  if (ret != NO_ERROR)
1598  {
1599  ASSERT_ERROR ();
1600  goto end;
1601  }
1602  }
1603 
1604  /*
1605  * We may need to update the max_key length if the mid key is
1606  * larger than the max key length. This will only happen when
1607  * the varying key length is larger than the fixed key length
1608  * in pathological cases like char(4)
1609  */
1610  new_max = btree_get_disk_size_of_key (&prefix_key);
1611  new_max = BTREE_GET_KEY_LEN_IN_PAGE (new_max);
1612  max_key_len = MAX (new_max, max_key_len);
1613 
1614  assert (node_level == 2);
1615  if (btree_connect_page (thread_p, &prefix_key, max_key_len, &load_args->leaf.vpid, load_args, node_level) ==
1616  NULL)
1617  {
1618  ASSERT_ERROR_AND_SET (ret);
1619  pr_clear_value (&prefix_key);
1620  goto end;
1621  }
1622 
1623  /* We always need to clear the prefix key. It is always a copy. */
1624  pr_clear_value (&prefix_key);
1625 
1626  btree_clear_key_value (&clear_last_key, &last_key);
1627 
1628  /* Learn the last key of the leaf page */
1629  assert (key_cnt > 0);
1630  if (spage_get_record (thread_p, load_args->leaf.pgptr, key_cnt, &temp_recdes, PEEK) != S_SUCCESS)
1631  {
1632  assert_release (false);
1633  ret = ER_FAILED;
1634  goto end;
1635  }
1636 
1637  ret =
1638  btree_read_record (thread_p, load_args->btid, load_args->leaf.pgptr, &temp_recdes, &last_key, &leaf_pnt,
1639  BTREE_LEAF_NODE, &clear_last_key, &last_key_offset, PEEK_KEY_VALUE, NULL);
1640  if (ret != NO_ERROR)
1641  {
1642  ASSERT_ERROR ();
1643  goto end;
1644  }
1645  }
1646  else
1647  {
1648  max_key_len = BTREE_GET_KEY_LEN_IN_PAGE (max_key_len);
1649 
1650  /* Insert this key to the parent level */
1651  assert (node_level == 2);
1652  if (btree_connect_page (thread_p, &first_key, max_key_len, &load_args->leaf.vpid, load_args, node_level) ==
1653  NULL)
1654  {
1655  ASSERT_ERROR_AND_SET (ret);
1656  goto end;
1657  }
1658  }
1659 
1660  btree_clear_key_value (&clear_first_key, &first_key);
1661 
1662  /* Proceed the current leaf page pointer to the next leaf page */
1663  pgbuf_unfix_and_init (thread_p, load_args->leaf.pgptr);
1664  load_args->leaf.vpid = next_vpid;
1665  load_args->leaf.pgptr = next_pageptr;
1666  next_pageptr = NULL;
1667 
1668  } /* while there are some more leaf pages */
1669 
1670 
1671  /* Update the non-leaf page header */
1672  header = btree_get_node_header (thread_p, load_args->nleaf.pgptr);
1673  if (header == NULL)
1674  {
1675  assert_release (false);
1676  ret = ER_FAILED;
1677  goto end;
1678  }
1679 
1680  *header = load_args->nleaf.hdr;
1681 
1682  /* Flush the last non-leaf page */
1683  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->nleaf.pgptr);
1684  load_args->nleaf.pgptr = NULL;
1685 
1686  /* Insert the pageid to the linked list */
1687  ret = list_add (&load_args->push_list, &load_args->nleaf.vpid);
1688  if (ret != NO_ERROR)
1689  {
1690  ASSERT_ERROR ();
1691  goto end;
1692  }
1693 
1694  btree_clear_key_value (&clear_last_key, &last_key);
1695 
1696  /*****************************************************
1697  PHASE II: Build the upper levels of tree
1698  ****************************************************/
1699 
1700  assert (node_level == 2);
1701 
1702  /* Switch the push and pop lists */
1703  load_args->pop_list = load_args->push_list;
1704  load_args->push_list = NULL;
1705 
1706  while (list_length (load_args->pop_list) > 1)
1707  {
1708  node_level++;
1709 
1710  /* while there are more than one page at the previous level do construct the next level */
1711 
1712  /* Initialize the first non-leaf page of current level */
1713  ret =
1714  btree_load_new_page (thread_p, load_args->btid->sys_btid, &load_args->nleaf.hdr, node_level,
1715  &load_args->nleaf.vpid, &load_args->nleaf.pgptr);
1716  if (ret != NO_ERROR)
1717  {
1718  ASSERT_ERROR ();
1719  goto end;
1720  }
1721  if (load_args->nleaf.pgptr == NULL)
1722  {
1723  assert_release (false);
1724  ret = ER_FAILED;
1725  goto end;
1726  }
1727 
1728  do
1729  { /* while pop_list is not empty */
1730  /* Get current pageid from the poplist */
1731  cur_nleafpgid = load_args->pop_list->pageid;
1732 
1733  /* Fetch the current page */
1734  cur_nleafpgptr = pgbuf_fix (thread_p, &cur_nleafpgid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
1735  if (cur_nleafpgptr == NULL)
1736  {
1737  ASSERT_ERROR_AND_SET (ret);
1738  goto end;
1739  }
1740 
1741  (void) pgbuf_check_page_ptype (thread_p, cur_nleafpgptr, PAGE_BTREE);
1742 
1743  /* obtain the header information for the current non-leaf page */
1744  header = btree_get_node_header (thread_p, cur_nleafpgptr);
1745  if (header == NULL)
1746  {
1747  assert_release (false);
1748  ret = ER_FAILED;
1749  goto end;
1750  }
1751 
1752  /* get the maximum key length on this leaf page */
1753  max_key_len = header->max_key_len;
1754 
1755  /* Learn the first key of the current page */
1756  /* Notice that since this is a non-leaf node */
1757  if (spage_get_record (thread_p, cur_nleafpgptr, 1, &temp_recdes, PEEK) != S_SUCCESS)
1758  {
1759  assert_release (false);
1760  ret = ER_FAILED;
1761  goto end;
1762  }
1763 
1764  ret =
1765  btree_read_record (thread_p, load_args->btid, cur_nleafpgptr, &temp_recdes, &first_key, &nleaf_pnt,
1766  BTREE_NON_LEAF_NODE, &clear_first_key, &first_key_offset, PEEK_KEY_VALUE, NULL);
1767  if (ret != NO_ERROR)
1768  {
1769  ASSERT_ERROR ();
1770  goto end;
1771  }
1772 
1773  max_key_len = BTREE_GET_KEY_LEN_IN_PAGE (max_key_len);
1774 
1775  /* set level to non-leaf page nleaf page could be changed in btree_connect_page */
1776 
1777  assert (node_level > 2);
1778 
1779  load_args->nleaf.hdr.node_level = node_level;
1780 
1781  /* Insert this key to the parent level */
1782  if (btree_connect_page (thread_p, &first_key, max_key_len, &cur_nleafpgid, load_args, node_level) == NULL)
1783  {
1784  ASSERT_ERROR_AND_SET (ret);
1785  goto end;
1786  }
1787 
1788  pgbuf_unfix_and_init (thread_p, cur_nleafpgptr);
1789 
1790  /* Remove this pageid from the pop list */
1791  list_remove_first (&load_args->pop_list);
1792 
1793  btree_clear_key_value (&clear_first_key, &first_key);
1794  }
1795  while (list_length (load_args->pop_list) > 0);
1796 
1797  /* FLUSH LAST NON-LEAF PAGE */
1798 
1799  /* Update the non-leaf page header */
1800  header = btree_get_node_header (thread_p, load_args->nleaf.pgptr);
1801  if (header == NULL)
1802  {
1803  assert_release (false);
1804  ret = ER_FAILED;
1805  goto end;
1806  }
1807 
1808  *header = load_args->nleaf.hdr;
1809 
1810  /* Flush the last non-leaf page */
1811  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->nleaf.pgptr);
1812  load_args->nleaf.pgptr = NULL;
1813 
1814  /* Insert the pageid to the linked list */
1815  ret = list_add (&load_args->push_list, &load_args->nleaf.vpid);
1816  if (ret != NO_ERROR)
1817  {
1818  ASSERT_ERROR ();
1819  goto end;
1820  }
1821 
1822  /* Switch push and pop lists */
1823  temp = load_args->pop_list;
1824  load_args->pop_list = load_args->push_list;
1825  load_args->push_list = temp;
1826  }
1827 
1828  /* Deallocate the last node (only one exists) */
1829  list_remove_first (&load_args->pop_list);
1830 
1831  /******************************************
1832  PHASE III: Update the root page
1833  *****************************************/
1834 
1835  /* Retrieve the last non-leaf page (the current one); guaranteed to exist */
1836  /* Fetch the current page */
1837  load_args->nleaf.pgptr =
1839  if (load_args->nleaf.pgptr == NULL)
1840  {
1841  ASSERT_ERROR_AND_SET (ret);
1842  goto end;
1843  }
1844  pgbuf_check_page_ptype (thread_p, load_args->nleaf.pgptr, PAGE_BTREE);
1845 
1846  /* Prepare the root header by using the last leaf node header */
1847  root_header->node.max_key_len = load_args->nleaf.hdr.max_key_len;
1848  root_header->node.node_level = node_level;
1849  VPID_SET_NULL (&(root_header->node.next_vpid));
1850  VPID_SET_NULL (&(root_header->node.prev_vpid));
1851  root_header->node.split_info.pivot = 0.0f;
1852  root_header->node.split_info.index = 0;
1853 
1854  if (load_args->btid->unique_pk)
1855  {
1856  root_header->num_nulls = n_nulls;
1857  root_header->num_oids = n_oids;
1858  root_header->num_keys = n_keys;
1859  root_header->unique_pk = load_args->btid->unique_pk;
1860 
1861  assert (BTREE_IS_UNIQUE (root_header->unique_pk));
1862  assert (BTREE_IS_PRIMARY_KEY (root_header->unique_pk) || !BTREE_IS_PRIMARY_KEY (root_header->unique_pk));
1863  }
1864  else
1865  {
1866  root_header->num_nulls = -1;
1867  root_header->num_oids = -1;
1868  root_header->num_keys = -1;
1869  root_header->unique_pk = 0;
1870  }
1871 
1872  COPY_OID (&(root_header->topclass_oid), &load_args->btid->topclass_oid);
1873 
1874  root_header->ovfid = load_args->btid->ovfid; /* structure copy */
1875  root_header->rev_level = BTREE_CURRENT_REV_LEVEL;
1876 
1877 #if defined (SERVER_MODE)
1878  root_header->creator_mvccid = logtb_get_current_mvccid (thread_p);
1879 #else /* !SERVER_MODE */ /* SA_MODE */
1880  root_header->creator_mvccid = MVCCID_NULL;
1881 #endif /* SA_MODE */
1882 
1883  /* change node header as root header */
1884  ret = btree_pack_root_header (&rec, root_header, load_args->btid->key_type);
1885  if (ret != NO_ERROR)
1886  {
1887  ASSERT_ERROR ();
1888  goto end;
1889  }
1890 
1891  if (spage_update (thread_p, load_args->nleaf.pgptr, HEADER, &rec) != SP_SUCCESS)
1892  {
1893  assert_release (false);
1894  ret = ER_FAILED;
1895  goto end;
1896  }
1897 
1898  /* move current ROOT page content to the first page allocated */
1899  btree_get_root_vpid_from_btid (thread_p, load_args->btid->sys_btid, &cur_nleafpgid);
1900  next_pageptr = pgbuf_fix (thread_p, &cur_nleafpgid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
1901  if (next_pageptr == NULL)
1902  {
1903  ASSERT_ERROR_AND_SET (ret);
1904  goto end;
1905  }
1906  assert (pgbuf_get_page_ptype (thread_p, next_pageptr) == PAGE_BTREE);
1907 
1908  memcpy (next_pageptr, load_args->nleaf.pgptr, DB_PAGESIZE);
1909  pgbuf_unfix_and_init (thread_p, load_args->nleaf.pgptr);
1910 
1911  load_args->nleaf.pgptr = next_pageptr;
1912  next_pageptr = NULL;
1913  load_args->nleaf.vpid = cur_nleafpgid;
1914 
1915  /* The root page must be logged, otherwise, in the event of a crash. The index may be gone. */
1916  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->nleaf.pgptr);
1917  load_args->nleaf.pgptr = NULL;
1918 
1919  assert (ret == NO_ERROR);
1920 
1921 end:
1922 
1923  /* cleanup */
1924  if (next_pageptr)
1925  {
1926  pgbuf_unfix_and_init (thread_p, next_pageptr);
1927  }
1928  if (cur_nleafpgptr)
1929  {
1930  pgbuf_unfix_and_init (thread_p, cur_nleafpgptr);
1931  }
1932  if (load_args->leaf.pgptr)
1933  {
1934  pgbuf_unfix_and_init (thread_p, load_args->leaf.pgptr);
1935  }
1936  if (load_args->nleaf.pgptr)
1937  {
1938  pgbuf_unfix_and_init (thread_p, load_args->nleaf.pgptr);
1939  }
1940  if (temp_data)
1941  {
1942  os_free_and_init (temp_data);
1943  }
1944 
1945  btree_clear_key_value (&clear_last_key, &last_key);
1946  btree_clear_key_value (&clear_first_key, &first_key);
1947 
1948  return ret;
1949 }
1950 
1951 /*
1952  * btree_log_page () - Save the contents of the buffer
1953  * return: nothing
1954  * vfid(in):
1955  * page_ptr(in): pointer to the page buffer to be saved
1956  *
1957  * Note: This function logs the contents of the given page and frees
1958  * the page after setting on the dirty bit.
1959  */
1960 static void
1961 btree_log_page (THREAD_ENTRY * thread_p, VFID * vfid, PAGE_PTR page_ptr)
1962 {
1963  LOG_DATA_ADDR addr; /* For recovery purposes */
1964 
1965  /* log the whole page for redo purposes. */
1966  addr.vfid = vfid;
1967  addr.pgptr = page_ptr;
1968  addr.offset = -1; /* irrelevant */
1969  log_append_redo_data (thread_p, RVBT_COPYPAGE, &addr, DB_PAGESIZE, page_ptr);
1970 
1971  pgbuf_set_dirty (thread_p, page_ptr, FREE);
1972  page_ptr = NULL;
1973 }
1974 
1975 /*
1976  * btree_load_new_page () - load a new b-tree page.
1977  *
1978  * return : Error code
1979  * thread_p (in) : Thread entry
1980  * btid (in) : B-tree identifier
1981  * header (in) : Node header for leaf/non-leaf nodes or NULL for overflow OID nodes
1982  * node_level (in) : Node level for leaf/non-leaf nodes or -1 for overflow OID nodes
1983  * vpid_new (out) : Output new page VPID
1984  * page_new (out) : Output new page
1985  */
1986 static int
1987 btree_load_new_page (THREAD_ENTRY * thread_p, const BTID * btid, BTREE_NODE_HEADER * header, int node_level,
1988  VPID * vpid_new, PAGE_PTR * page_new)
1989 {
1990  int error_code = NO_ERROR;
1991 
1992  assert ((header != NULL && node_level >= 1) /* leaf, non-leaf */
1993  || (header == NULL && node_level == -1)); /* overflow */
1994  assert (log_check_system_op_is_started (thread_p)); /* need system operation */
1995 
1996  /* we need to commit page allocations. if loading index is aborted, the entire file is destroyed. */
1997  log_sysop_start (thread_p);
1998 
1999  /* allocate new page */
2000  error_code = file_alloc (thread_p, &btid->vfid, btree_initialize_new_page, NULL, vpid_new, page_new);
2001  if (error_code != NO_ERROR)
2002  {
2003  ASSERT_ERROR ();
2004  goto end;
2005  }
2006  if (*page_new == NULL)
2007  {
2008  assert_release (false);
2009  error_code = ER_FAILED;
2010  goto end;
2011  }
2012  (void) pgbuf_check_page_ptype (thread_p, *page_new, PAGE_BTREE);
2013 
2014  if (header)
2015  { /* This is going to be a leaf or non-leaf page */
2016  /* Insert the node header (with initial values) to the leaf node */
2017  header->node_level = node_level;
2018  header->max_key_len = 0;
2019  VPID_SET_NULL (&header->next_vpid);
2020  VPID_SET_NULL (&header->prev_vpid);
2021  header->split_info.pivot = 0.0f;
2022  header->split_info.index = 0;
2023 
2024  error_code = btree_init_node_header (thread_p, &btid->vfid, *page_new, header, false);
2025  if (error_code != NO_ERROR)
2026  {
2027  ASSERT_ERROR ();
2028  pgbuf_unfix_and_init (thread_p, *page_new);
2029  goto end;
2030  }
2031  }
2032  else
2033  { /* This is going to be an overflow page */
2034  BTREE_OVERFLOW_HEADER ovf_header_info;
2035 
2036  assert (node_level == -1);
2037  VPID_SET_NULL (&ovf_header_info.next_vpid);
2038 
2039  error_code = btree_init_overflow_header (thread_p, *page_new, &ovf_header_info);
2040  if (error_code != NO_ERROR)
2041  {
2042  ASSERT_ERROR ();
2043  pgbuf_unfix_and_init (thread_p, *page_new);
2044  goto end;
2045  }
2046  }
2047 
2048  assert (error_code == NO_ERROR);
2049 
2050 end:
2051  if (error_code != NO_ERROR)
2052  {
2053  log_sysop_abort (thread_p);
2054  }
2055  else
2056  {
2057  log_sysop_commit (thread_p);
2058  }
2059 
2060  return error_code;
2061 }
2062 
2063 /*
2064  * btree_proceed_leaf () - Proceed the current leaf page to a new one
2065  * return: PAGE_PTR (pointer to the new leaf page, or NULL in
2066  * case of an error).
2067  * load_args(in): Collection of information on how to build B+tree.
2068  *
2069  * Note: This function proceeds the current leaf page pointer from a
2070  * full leaf page to a new (completely empty) one. It first
2071  * allocates a new leaf page and connects it to the current
2072  * leaf page; then, it dumps the current one; and finally makes
2073  * the new leaf page "current".
2074  */
2075 static PAGE_PTR
2077 {
2078  /* Local variables for managing leaf & overflow pages */
2079  VPID new_leafpgid;
2080  PAGE_PTR new_leafpgptr = NULL;
2081  BTREE_NODE_HEADER new_leafhdr, *header = NULL;
2082  RECDES temp_recdes; /* Temporary record descriptor; */
2083  OR_ALIGNED_BUF (sizeof (BTREE_NODE_HEADER)) a_temp_data;
2084 
2085  temp_recdes.data = OR_ALIGNED_BUF_START (a_temp_data);
2086  temp_recdes.area_size = sizeof (BTREE_NODE_HEADER);
2087 
2088  /* Allocate the new leaf page */
2089  if (btree_load_new_page (thread_p, load_args->btid->sys_btid, &new_leafhdr, 1, &new_leafpgid, &new_leafpgptr)
2090  != NO_ERROR)
2091  {
2092  ASSERT_ERROR ();
2093  return NULL;
2094  }
2095  if (new_leafpgptr == NULL)
2096  {
2097  assert_release (false);
2098  return NULL;
2099  }
2100 
2101  /* new leaf update header */
2102  new_leafhdr.prev_vpid = load_args->leaf.vpid;
2103 
2104  header = btree_get_node_header (thread_p, new_leafpgptr);
2105  if (header == NULL)
2106  {
2107  pgbuf_unfix_and_init (thread_p, new_leafpgptr);
2108  return NULL;
2109  }
2110 
2111  *header = new_leafhdr; /* update header */
2112 
2113  /* current leaf update header */
2114  /* make the current leaf page point to the new one */
2115  load_args->leaf.hdr.next_vpid = new_leafpgid;
2116 
2117  /* and the new leaf point to the current one */
2118  header = btree_get_node_header (thread_p, load_args->leaf.pgptr);
2119  if (header == NULL)
2120  {
2121  pgbuf_unfix_and_init (thread_p, new_leafpgptr);
2122  return NULL;
2123  }
2124 
2125  *header = load_args->leaf.hdr;
2126 
2127  /* Flush the current leaf page */
2128  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->leaf.pgptr);
2129  load_args->leaf.pgptr = NULL;
2130 
2131  /* Make the new leaf page become the current one */
2132  load_args->leaf.vpid = new_leafpgid;
2133  load_args->leaf.pgptr = new_leafpgptr;
2134  load_args->leaf.hdr = new_leafhdr;
2135 
2136  return load_args->leaf.pgptr;
2137 }
2138 
2139 /*
2140  * btree_first_oid () - Prepare record for the key and its first oid
2141  * return: int
2142  * this_key(in): Key
2143  * class_oid(in):
2144  * first_oid(in): First OID associated with this key; inserted into the
2145  * record.
2146  * load_args(in): Contains fields specifying where & how to create the record
2147  *
2148  * Note: This function prepares the leaf record for the given key and
2149  * its first OID at the storage location specified by
2150  * load_args->out_recdes field.
2151  */
2152 static int
2153 btree_first_oid (THREAD_ENTRY * thread_p, DB_VALUE * this_key, OID * class_oid, OID * first_oid,
2154  MVCC_REC_HEADER * p_mvcc_rec_header, LOAD_ARGS * load_args)
2155 {
2156  int key_len;
2157  int key_type;
2158  int error;
2160 
2161  assert (load_args->out_recdes == &load_args->leaf_nleaf_recdes);
2162 
2163  /* form the leaf record (create the header & insert the key) */
2164  key_len = load_args->cur_key_len = btree_get_disk_size_of_key (this_key);
2165  if (key_len < BTREE_MAX_KEYLEN_INPAGE)
2166  {
2167  key_type = BTREE_NORMAL_KEY;
2168  }
2169  else
2170  {
2171  key_type = BTREE_OVERFLOW_KEY;
2172  if (VFID_ISNULL (&load_args->btid->ovfid))
2173  {
2174  error = btree_create_overflow_key_file (thread_p, load_args->btid);
2175  if (error != NO_ERROR)
2176  {
2177  return error;
2178  }
2179  }
2180  }
2181  btree_mvcc_info_from_heap_mvcc_header (p_mvcc_rec_header, &mvcc_info);
2182  error =
2183  btree_write_record (thread_p, load_args->btid, NULL, this_key, BTREE_LEAF_NODE, key_type, key_len, true, class_oid,
2184  first_oid, &mvcc_info, load_args->out_recdes);
2185  if (error != NO_ERROR)
2186  {
2187  /* this must be an overflow key insertion failure, we assume the overflow manager has logged an error. */
2188  return error;
2189  }
2190 
2191  /* Set the location where the new oid should be inserted */
2192  load_args->new_pos = (load_args->out_recdes->data + load_args->out_recdes->length);
2193  assert (load_args->out_recdes->length <= load_args->out_recdes->area_size);
2194 
2195  /* Set the current key value to this_key */
2196  pr_clear_value (&load_args->current_key); /* clear previous value */
2197  load_args->cur_key_len = key_len;
2198 
2199  return pr_clone_value (this_key, &load_args->current_key);
2200 }
2201 
2202 /*
2203  * btree_construct_leafs () - Output function for index sorting;constructs leaf
2204  * nodes
2205  * return: int
2206  * in_recdes(in): specifies the next sort item in the sorting order.
2207  * arg(in): output arguments; provides information about how to use the
2208  * next item in the sorted list to construct the leaf nodes of
2209  * the Btree.
2210  *
2211  * Note: This function creates the btree leaf nodes. It is passed
2212  * by the "btree_index_sort" function to the "sort_listfile" function
2213  * to use the sort items to build the records and pages of the btree.
2214  */
2215 static int
2216 btree_construct_leafs (THREAD_ENTRY * thread_p, const RECDES * in_recdes, void *arg)
2217 {
2218  int ret = NO_ERROR;
2220  DB_VALUE this_key; /* Key value in this sorted item (specified with in_recdes) */
2221  OID this_class_oid = oid_Null_oid; /* Class OID value in this sorted item */
2222  OID this_oid = oid_Null_oid; /* OID value in this sorted item */
2223  OID original_oid = oid_Null_oid;
2224  OID original_class_oid = oid_Null_oid;
2225  int sp_success;
2226  int cur_maxspace;
2227  INT16 slotid;
2228  bool same_key = true;
2229  VPID new_ovfpgid;
2230  PAGE_PTR new_ovfpgptr = NULL;
2231  OR_BUF buf;
2232  bool copy = false;
2233  RECDES sort_key_recdes, *recdes;
2234  char *next;
2235  int next_size;
2236  int key_size = -1;
2237  BTREE_OVERFLOW_HEADER *ovf_header = NULL;
2238 
2239  int oid_size = OR_OID_SIZE;
2240  int fixed_mvccid_size = 0;
2242  /* TODO: What about using only MVCC info here? */
2243  MVCC_REC_HEADER mvcc_header;
2244  MVCC_REC_HEADER original_mvcc_header;
2245 
2246  char notify_vacuum_rv_data_buffer[IO_MAX_PAGE_SIZE + BTREE_MAX_ALIGN];
2247  char *notify_vacuum_rv_data_bufalign = PTR_ALIGN (notify_vacuum_rv_data_buffer, BTREE_MAX_ALIGN);
2248  char *notify_vacuum_rv_data = notify_vacuum_rv_data_bufalign;
2249  int notify_vacuum_rv_data_capacity = IO_MAX_PAGE_SIZE;
2250  int notify_vacuum_rv_data_length = 0;
2251 
2252  load_args = (LOAD_ARGS *) arg;
2253 
2254 #if defined (SERVER_MODE)
2255  /* Make sure MVCCID for current transaction is generated. */
2256  (void) logtb_get_current_mvccid (thread_p);
2257 #endif /* SERVER_MODE */
2258 
2259  fixed_mvccid_size = 2 * OR_MVCCID_SIZE;
2260  if (BTREE_IS_UNIQUE (load_args->btid->unique_pk))
2261  {
2262  oid_size = 2 * OR_OID_SIZE;
2263  }
2264 
2265  sort_key_recdes = *in_recdes;
2266  recdes = &sort_key_recdes;
2267 
2268  next_size = sizeof (char *);
2269 
2270  for (;;)
2271  { /* Infinite loop; will exit with break statement */
2272 
2273  next = *(char **) recdes->data; /* save forward link */
2274 
2275  /* First decompose the input record into the key and oid components */
2276  or_init (&buf, recdes->data, recdes->length);
2277  assert (buf.ptr == PTR_ALIGN (buf.ptr, MAX_ALIGNMENT));
2278 
2279  /* Skip forward link, value_has_null */
2280  or_advance (&buf, next_size + OR_INT_SIZE);
2281 
2282  assert (buf.ptr == PTR_ALIGN (buf.ptr, INT_ALIGNMENT));
2283 
2284  /* Instance level uniqueness checking */
2285  if (BTREE_IS_UNIQUE (load_args->btid->unique_pk))
2286  { /* unique index */
2287  /* extract class OID */
2288  ret = or_get_oid (&buf, &this_class_oid);
2289  if (ret != NO_ERROR)
2290  {
2291  goto error;
2292  }
2293  }
2294 
2295  /* Get OID */
2296  ret = or_get_oid (&buf, &this_oid);
2297  if (ret != NO_ERROR)
2298  {
2299  goto error;
2300  }
2301 
2302  /* Create MVCC header */
2303  BTREE_INIT_MVCC_HEADER (&mvcc_header);
2304 
2305  ret = or_get_mvccid (&buf, &MVCC_GET_INSID (&mvcc_header));
2306  if (ret != NO_ERROR)
2307  {
2308  goto error;
2309  }
2310 
2311  ret = or_get_mvccid (&buf, &MVCC_GET_DELID (&mvcc_header));
2312  if (ret != NO_ERROR)
2313  {
2314  goto error;
2315  }
2316 
2317 #if defined(SERVER_MODE)
2318  if (MVCC_GET_INSID (&mvcc_header) != MVCCID_ALL_VISIBLE)
2319  {
2320  /* Set valid insert MVCCID flag */
2322  }
2323 #else
2324  /* all inserted OIDs are created as visible in stand-alone */
2325  MVCC_SET_INSID (&mvcc_header, MVCCID_ALL_VISIBLE);
2326 #endif /* SERVER_MODE */
2327 
2328  if (MVCC_GET_DELID (&mvcc_header) != MVCCID_NULL)
2329  {
2330 #if defined(SERVER_MODE)
2331  /* Set valid delete MVCCID */
2333 #else
2334  /* standalone : ignore deleted OID */
2335  continue;
2336 #endif /* SERVER_MODE */
2337  }
2338 
2339  /* Save OID, class OID and MVCC header since they may be replaced. */
2340  COPY_OID (&original_oid, &this_oid);
2341  COPY_OID (&original_class_oid, &this_class_oid);
2342  original_mvcc_header = mvcc_header;
2343 
2344  assert (buf.ptr == PTR_ALIGN (buf.ptr, INT_ALIGNMENT));
2345 
2347  {
2349  "DEBUG_BTREE: load new object(%d, %d, %d) class(%d, %d, %d) and btid(%d, (%d, %d)) with "
2350  "mvccinfo=%llu| %llu", this_oid.volid, this_oid.pageid, this_oid.slotid, this_class_oid.volid,
2351  this_class_oid.pageid, this_class_oid.slotid, load_args->btid->sys_btid->root_pageid,
2352  load_args->btid->sys_btid->vfid.volid, load_args->btid->sys_btid->vfid.fileid,
2353  MVCC_GET_INSID (&mvcc_header), MVCC_GET_DELID (&mvcc_header));
2354  }
2355 
2356  /* Do not copy the string--just use the pointer. The pr_ routines for strings and sets have different semantics
2357  * for length. */
2358  if (TP_DOMAIN_TYPE (load_args->btid->key_type) == DB_TYPE_MIDXKEY)
2359  {
2360  key_size = CAST_STRLEN (buf.endptr - buf.ptr);
2361  }
2362 
2363  ret = load_args->btid->key_type->type->data_readval (&buf, &this_key, load_args->btid->key_type, key_size, copy,
2364  NULL, 0);
2365  if (ret != NO_ERROR)
2366  {
2368  goto error;
2369  }
2370 
2371  /* Find out if this is the first call to this function */
2372  if (VPID_ISNULL (&(load_args->leaf.vpid)))
2373  {
2374  /* This is the first call to this function; so, initialize some fields in the LOAD_ARGS structure */
2375 
2376  /* Allocate the first page for the index */
2377  ret =
2378  btree_load_new_page (thread_p, load_args->btid->sys_btid, &load_args->leaf.hdr, 1, &load_args->leaf.vpid,
2379  &load_args->leaf.pgptr);
2380  if (ret != NO_ERROR)
2381  {
2382  ASSERT_ERROR ();
2383  goto error;
2384  }
2385  if (load_args->leaf.pgptr == NULL || VPID_ISNULL (&load_args->leaf.vpid))
2386  {
2387  assert_release (false);
2388  goto error;
2389  }
2390  /* Save first leaf VPID. */
2391  load_args->vpid_first_leaf = load_args->leaf.vpid;
2392 
2393 #if 0 /* TODO: currently not used */
2394  load_args->first_leafpgid = load_args->leaf.vpid;
2395 #endif
2396  load_args->overflowing = false;
2397  assert (load_args->ovf.pgptr == NULL);
2398 
2399  /* Create the first record of the current page in main memory */
2400  load_args->out_recdes = &load_args->leaf_nleaf_recdes;
2401  ret = btree_first_oid (thread_p, &this_key, &this_class_oid, &this_oid, &mvcc_header, load_args);
2402  if (ret != NO_ERROR)
2403  {
2404  goto error;
2405  }
2406 
2407  if (!MVCC_IS_HEADER_DELID_VALID (&mvcc_header))
2408  {
2409  /* Object was not deleted, increment curr_non_del_obj_count */
2410  load_args->curr_non_del_obj_count = 1;
2411 
2412  /* Increment the key counter if object is not deleted */
2413  (load_args->n_keys)++;
2414  }
2415  else
2416  {
2417  /* Object is deleted, initialize curr_non_del_obj_count as 0 */
2418  load_args->curr_non_del_obj_count = 0;
2419  }
2420 
2422  load_args->curr_rec_obj_count = 1;
2423 
2424 #if !defined (NDEBUG)
2425  btree_check_valid_record (thread_p, load_args->btid, load_args->out_recdes, BTREE_LEAF_NODE, NULL);
2426 #endif
2427  }
2428  else
2429  { /* This is not the first call to this function */
2430  int c = DB_UNK;
2431 
2432  /*
2433  * Compare the received key with the current one.
2434  * If different, then dump the current record and create a new record.
2435  */
2436 
2437  c = btree_compare_key (&this_key, &load_args->current_key, load_args->btid->key_type, 0, 1, NULL);
2438  if (c == DB_EQ || c == DB_GT)
2439  {
2440  ; /* ok */
2441  }
2442  else
2443  {
2444  assert_release (false);
2445  goto error;
2446  }
2447 
2448  same_key = (c == DB_EQ) ? true : false;
2449 
2450  /* EQUALITY test only - doesn't care the reverse index */
2451 
2452  if (same_key)
2453  {
2454  /* This key (retrieved key) is the same with the current one. */
2455  load_args->curr_rec_obj_count++;
2456  if (!MVCC_IS_HEADER_DELID_VALID (&mvcc_header))
2457  {
2458  /* TODO: Rewrite btree_construct_leafs. It's almost impossible to follow. */
2459  load_args->curr_non_del_obj_count++;
2460  if (load_args->curr_non_del_obj_count > 1 && BTREE_IS_UNIQUE (load_args->btid->unique_pk))
2461  {
2462  /* Unique constrain violation - more than one visible records for this key. */
2463  BTREE_SET_UNIQUE_VIOLATION_ERROR (thread_p, &this_key, &this_oid, &this_class_oid,
2464  load_args->btid->sys_btid, load_args->bt_name);
2465  ret = ER_BTREE_UNIQUE_FAILED;
2466  goto error;
2467  }
2468  if (load_args->curr_non_del_obj_count == 1)
2469  {
2470  /* When first non-deleted object is found, we must increment that number of keys for statistics. */
2471  (load_args->n_keys)++;
2472 
2473  if (BTREE_IS_UNIQUE (load_args->btid->unique_pk))
2474  {
2475  /* this is the first non-deleted OID of the key; it must be placed as the first OID */
2476  BTREE_MVCC_INFO first_mvcc_info;
2477  OID first_oid, first_class_oid;
2478  int offset = 0;
2479 
2480  /* Retrieve the first OID from leaf record */
2481  ret =
2482  btree_leaf_get_first_object (load_args->btid, &load_args->leaf_nleaf_recdes, &first_oid,
2483  &first_class_oid, &first_mvcc_info);
2484  if (ret != NO_ERROR)
2485  {
2486  goto error;
2487  }
2488 
2489  /* replace with current OID (might move memory in record) */
2490  btree_mvcc_info_from_heap_mvcc_header (&mvcc_header, &mvcc_info);
2491  btree_leaf_change_first_object (thread_p, &load_args->leaf_nleaf_recdes, load_args->btid,
2492  &this_oid, &this_class_oid, &mvcc_info, &offset, NULL, NULL);
2493  if (ret != NO_ERROR)
2494  {
2495  goto error;
2496  }
2497 
2498  if (!load_args->overflowing)
2499  {
2500  /* Update load_args->new_pos in case record has grown after replace */
2501  load_args->new_pos += offset;
2502  }
2503 
2504  assert (load_args->leaf_nleaf_recdes.length <= load_args->leaf_nleaf_recdes.area_size);
2505 #if !defined (NDEBUG)
2506  btree_check_valid_record (thread_p, load_args->btid, &load_args->leaf_nleaf_recdes,
2508 #endif
2509 
2510  /* save first OID as current OID, to be written */
2511  COPY_OID (&this_oid, &first_oid);
2512  COPY_OID (&this_class_oid, &first_class_oid);
2513  btree_mvcc_info_to_heap_mvcc_header (&first_mvcc_info, &mvcc_header);
2514  }
2515  }
2516  }
2517 
2518  /* Check if there is space in the memory record for the new OID. If not dump the current record and
2519  * create a new record. */
2520 
2521  if (load_args->curr_rec_obj_count > load_args->curr_rec_max_obj_count)
2522  { /* There is no space for the new oid */
2523  if (load_args->overflowing == true)
2524  {
2525  /* Store the record in current overflow page */
2526  assert (load_args->out_recdes == &load_args->ovf_recdes);
2527  sp_success = spage_insert (thread_p, load_args->ovf.pgptr, &load_args->ovf_recdes, &slotid);
2528  if (sp_success != SP_SUCCESS)
2529  {
2530  goto error;
2531  }
2532 
2533  assert (slotid > 0);
2534 
2535  /* Allocate the new overflow page */
2536  ret =
2537  btree_load_new_page (thread_p, load_args->btid->sys_btid, NULL, -1, &new_ovfpgid,
2538  &new_ovfpgptr);
2539  if (ret != NO_ERROR)
2540  {
2541  ASSERT_ERROR ();
2542  goto error;
2543  }
2544  if (new_ovfpgptr == NULL)
2545  {
2546  assert_release (false);
2547  ret = ER_FAILED;
2548  goto error;
2549  }
2550 
2551  /* make the current overflow page point to the new one */
2552  ovf_header = btree_get_overflow_header (thread_p, load_args->ovf.pgptr);
2553  if (ovf_header == NULL)
2554  {
2555  goto error;
2556  }
2557 
2558  ovf_header->next_vpid = new_ovfpgid;
2559 
2560  /* Save the current overflow page */
2561  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->ovf.pgptr);
2562  load_args->ovf.pgptr = NULL;
2563 
2564  /* Make the new overflow page become the current one */
2565  load_args->ovf.vpid = new_ovfpgid;
2566  load_args->ovf.pgptr = new_ovfpgptr;
2567  new_ovfpgptr = NULL;
2568  }
2569  else
2570  { /* Current page is a leaf page */
2571  assert (load_args->out_recdes == &load_args->leaf_nleaf_recdes);
2572  /* Allocate the new overflow page */
2573  ret =
2574  btree_load_new_page (thread_p, load_args->btid->sys_btid, NULL, -1, &load_args->ovf.vpid,
2575  &load_args->ovf.pgptr);
2576  if (ret != NO_ERROR)
2577  {
2578  ASSERT_ERROR ();
2579  goto error;
2580  }
2581  if (load_args->ovf.pgptr == NULL)
2582  {
2583  assert_release (false);
2584  goto error;
2585  }
2586 
2587  /* Connect the new overflow page to the leaf page */
2588  btree_leaf_record_change_overflow_link (thread_p, load_args->btid, &load_args->leaf_nleaf_recdes,
2589  &load_args->ovf.vpid, NULL, NULL);
2590 
2591  load_args->overflowing = true;
2592 
2593  /* Set out_recdes to ovf_recdes. */
2594  load_args->out_recdes = &load_args->ovf_recdes;
2595  } /* Current page is a leaf page */
2596 
2597  /* Initialize the memory area for the next record */
2598  assert (load_args->out_recdes == &load_args->ovf_recdes);
2599  load_args->out_recdes->length = 0;
2600  load_args->new_pos = load_args->out_recdes->data;
2601  load_args->curr_rec_max_obj_count =
2602  BTREE_MAX_OIDCOUNT_IN_SIZE (load_args->btid,
2603  spage_max_space_for_new_record (thread_p, load_args->ovf.pgptr));
2604  load_args->curr_rec_obj_count = 1;
2605  } /* no space for the new OID */
2606 
2607  if (load_args->overflowing || BTREE_IS_UNIQUE (load_args->btid->unique_pk))
2608  {
2609  /* all overflow OIDs have fixed header size; also, all OIDs of a unique index key (except the first
2610  * one) have fixed size */
2611  BTREE_MVCC_SET_HEADER_FIXED_SIZE (&mvcc_header);
2612  }
2613 
2614  /* Insert new OID, class OID (for unique), and MVCCID's. */
2615  /* Insert OID (and MVCC flags) */
2616  btree_set_mvcc_flags_into_oid (&mvcc_header, &this_oid);
2617  OR_PUT_OID (load_args->new_pos, &this_oid);
2618  load_args->out_recdes->length += OR_OID_SIZE;
2619  load_args->new_pos += OR_OID_SIZE;
2620 
2621  if (BTREE_IS_UNIQUE (load_args->btid->unique_pk))
2622  {
2623  /* Insert class OID */
2624  OR_PUT_OID (load_args->new_pos, &this_class_oid);
2625  load_args->out_recdes->length += OR_OID_SIZE;
2626  load_args->new_pos += OR_OID_SIZE;
2627  }
2628 
2629  btree_mvcc_info_from_heap_mvcc_header (&mvcc_header, &mvcc_info);
2630  /* Insert MVCCID's */
2631  load_args->out_recdes->length += btree_packed_mvccinfo_size (&mvcc_info);
2632  load_args->new_pos = btree_pack_mvccinfo (load_args->new_pos, &mvcc_info);
2633 
2634  assert (load_args->out_recdes->length <= load_args->out_recdes->area_size);
2635 #if !defined (NDEBUG)
2636  btree_check_valid_record (thread_p, load_args->btid, load_args->out_recdes,
2638 #endif
2639  } /* same key */
2640  else
2641  {
2642  /* Current key is finished; dump this output record to the disk page */
2643 
2644  /* Insert current leaf record */
2645  cur_maxspace = spage_max_space_for_new_record (thread_p, load_args->leaf.pgptr);
2646  if (((cur_maxspace - load_args->leaf_nleaf_recdes.length) < LOAD_FIXED_EMPTY_FOR_LEAF)
2647  && (spage_number_of_records (load_args->leaf.pgptr) > 1))
2648  {
2649  /* New record does not fit into the current leaf page (within the threshold value); so allocate a new
2650  * leaf page and dump the current leaf page. */
2651  if (btree_proceed_leaf (thread_p, load_args) == NULL)
2652  {
2653  goto error;
2654  }
2655  } /* get a new leaf */
2656 
2657  /* Insert the record to the current leaf page */
2658  sp_success =
2659  spage_insert (thread_p, load_args->leaf.pgptr, &load_args->leaf_nleaf_recdes,
2660  &load_args->last_leaf_insert_slotid);
2661  if (sp_success != SP_SUCCESS)
2662  {
2663  goto error;
2664  }
2665 
2666  assert (load_args->last_leaf_insert_slotid > 0);
2667 
2668  /* Update the node header information for this record */
2669  if (load_args->cur_key_len >= BTREE_MAX_KEYLEN_INPAGE)
2670  {
2671  if (load_args->leaf.hdr.max_key_len < DISK_VPID_SIZE)
2672  {
2673  load_args->leaf.hdr.max_key_len = DISK_VPID_SIZE;
2674  }
2675  }
2676  else
2677  {
2678  if (load_args->leaf.hdr.max_key_len < load_args->cur_key_len)
2679  {
2680  load_args->leaf.hdr.max_key_len = load_args->cur_key_len;
2681  }
2682  }
2683 
2684  if (load_args->overflowing)
2685  {
2686  /* Insert the new record to the current overflow page and flush this page */
2687 
2688  assert (load_args->out_recdes == &load_args->ovf_recdes);
2689 
2690  /* Store the record in current overflow page */
2691  sp_success = spage_insert (thread_p, load_args->ovf.pgptr, load_args->out_recdes, &slotid);
2692  if (sp_success != SP_SUCCESS)
2693  {
2694  goto error;
2695  }
2696 
2697  assert (slotid > 0);
2698 
2699  /* Save the current overflow page */
2700  btree_log_page (thread_p, &load_args->btid->sys_btid->vfid, load_args->ovf.pgptr);
2701  load_args->ovf.pgptr = NULL;
2702 
2703  /* Turn off the overflowing mode */
2704  load_args->overflowing = false;
2705  } /* Current page is an overflow page */
2706  else
2707  {
2708  assert (load_args->out_recdes == &load_args->leaf_nleaf_recdes);
2709  }
2710 
2711  /* Create the first part of the next record in main memory */
2712  load_args->out_recdes = &load_args->leaf_nleaf_recdes;
2713  ret = btree_first_oid (thread_p, &this_key, &this_class_oid, &this_oid, &mvcc_header, load_args);
2714  if (ret != NO_ERROR)
2715  {
2716  goto error;
2717  }
2718 
2719  if (!MVCC_IS_HEADER_DELID_VALID (&mvcc_header))
2720  {
2721  /* Object was not deleted, increment curr_non_del_obj_count. */
2722  load_args->curr_non_del_obj_count = 1;
2723  (load_args->n_keys)++; /* Increment the key counter */
2724  }
2725  else
2726  {
2727  /* Object is deleted, initialize curr_non_del_obj_count as 0. */
2728  load_args->curr_non_del_obj_count = 0;
2729  }
2730 
2732  load_args->curr_rec_obj_count = 1;
2733 
2734 #if !defined (NDEBUG)
2735  btree_check_valid_record (thread_p, load_args->btid, load_args->out_recdes, BTREE_LEAF_NODE, NULL);
2736 #endif
2737  } /* different key */
2738  }
2739 
2741  {
2743  "DEBUG_BTREE: load added object(%d, %d, %d) "
2744  "class(%d, %d, %d) and btid(%d, (%d, %d)) with mvccinfo=%llu | %llu", this_oid.volid,
2745  this_oid.pageid, this_oid.slotid, this_class_oid.volid, this_class_oid.pageid,
2746  this_class_oid.slotid, load_args->btid->sys_btid->root_pageid,
2747  load_args->btid->sys_btid->vfid.volid, load_args->btid->sys_btid->vfid.fileid,
2748  MVCC_GET_INSID (&mvcc_header), MVCC_GET_DELID (&mvcc_header));
2749  }
2750 
2751  /* Some objects have been recently deleted and couldn't be filtered (because there may be running transaction
2752  * that can still see them. However, they must be vacuumed later. Vacuum can only find them by parsing log,
2753  * therefore some log records are required. These are dummy records with the sole purpose of notifying vacuum.
2754  * Since this_oid, this_class_oid and mvcc_header could be replaced in case first object of unique index had to
2755  * be swapped, we will use original_oid, original_class_oid and original_mvcc_header to log object load for
2756  * vacuum. */
2757  if (MVCC_IS_HEADER_DELID_VALID (&original_mvcc_header)
2758  || MVCC_IS_HEADER_INSID_NOT_ALL_VISIBLE (&original_mvcc_header))
2759  {
2760  /* There is something to vacuum for this object */
2761  char *pgptr;
2762 
2763  pgptr = (load_args->overflowing ? load_args->ovf.pgptr : load_args->leaf.pgptr);
2764 
2765  /* clear flags for logging */
2766  btree_clear_mvcc_flags_from_oid (&original_oid);
2767 
2769  {
2771  "DEBUG_BTREE: load notify vacuum object(%d, %d, %d) "
2772  "class(%d, %d, %d) and btid(%d, (%d, %d)) with mvccinfo=%llu | %llu",
2773  original_oid.volid, original_oid.pageid, original_oid.slotid, original_class_oid.volid,
2774  original_class_oid.pageid, original_class_oid.slotid,
2775  load_args->btid->sys_btid->root_pageid, load_args->btid->sys_btid->vfid.volid,
2776  load_args->btid->sys_btid->vfid.fileid, MVCC_GET_INSID (&original_mvcc_header),
2777  MVCC_GET_DELID (&original_mvcc_header));
2778  }
2779 
2780  /* append log data */
2781  btree_mvcc_info_from_heap_mvcc_header (&original_mvcc_header, &mvcc_info);
2782  ret =
2783  btree_rv_save_keyval_for_undo (load_args->btid, &this_key, &original_class_oid, &original_oid, &mvcc_info,
2784  BTREE_OP_NOTIFY_VACUUM, notify_vacuum_rv_data_bufalign,
2785  &notify_vacuum_rv_data, &notify_vacuum_rv_data_capacity,
2786  &notify_vacuum_rv_data_length);
2787  if (ret != NO_ERROR)
2788  {
2789  goto error;
2790  }
2791  log_append_undo_data2 (thread_p, RVBT_MVCC_NOTIFY_VACUUM, &load_args->btid->sys_btid->vfid, NULL, -1,
2792  notify_vacuum_rv_data_length, notify_vacuum_rv_data);
2793  pgbuf_set_dirty (thread_p, pgptr, DONT_FREE);
2794  }
2795 
2796  /* set level 1 to leaf */
2797  load_args->leaf.hdr.node_level = 1;
2798 
2799  if (this_key.need_clear)
2800  {
2801  copy = true;
2802  }
2803 
2804  btree_clear_key_value (&copy, &this_key);
2805 
2806  if (next)
2807  { /* move to next link */
2808  recdes->data = next;
2809  recdes->length = SORT_RECORD_LENGTH (next);
2810  }
2811  else
2812  {
2813  break; /* exit infinite loop */
2814  }
2815 
2816  }
2817 
2818  if (notify_vacuum_rv_data != NULL && notify_vacuum_rv_data != notify_vacuum_rv_data_bufalign)
2819  {
2820  db_private_free (thread_p, notify_vacuum_rv_data);
2821  }
2822 
2823  assert (ret == NO_ERROR);
2824  return ret;
2825 
2826 error:
2827  if (load_args->leaf.pgptr)
2828  {
2829  pgbuf_unfix_and_init (thread_p, load_args->leaf.pgptr);
2830  }
2831  if (load_args->ovf.pgptr)
2832  {
2833  pgbuf_unfix_and_init (thread_p, load_args->ovf.pgptr);
2834  }
2835  if (new_ovfpgptr)
2836  {
2837  pgbuf_unfix_and_init (thread_p, new_ovfpgptr);
2838  }
2839  btree_clear_key_value (&copy, &this_key);
2840 
2841  if (notify_vacuum_rv_data != NULL && notify_vacuum_rv_data != notify_vacuum_rv_data_bufalign)
2842  {
2843  db_private_free (thread_p, notify_vacuum_rv_data);
2844  }
2845 
2846  assert (er_errid () != NO_ERROR);
2847  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
2848 }
2849 
2850 #if defined(CUBRID_DEBUG)
2851 /*
2852  * btree_dump_sort_output () - Sample output function for index sorting
2853  * return: NO_ERROR
2854  * recdes(in):
2855  * load_args(in):
2856  *
2857  * Note: This function is a debugging function. It is passed by the
2858  * btree_index_sort function to the sort_listfile function to print
2859  * out the contents of the sort items once they are obtained in
2860  * the requested sorting order.
2861  *
2862  */
2863 static int
2864 btree_dump_sort_output (const RECDES * recdes, LOAD_ARGS * load_args)
2865 {
2866  OID this_oid;
2867  DB_VALUE this_key;
2868  OR_BUF buf;
2869  bool copy = false;
2870  int key_size = -1;
2871  int ret = NO_ERROR;
2872 
2873  /* First decompose the input record into the key and oid components */
2874  or_init (&buf, recdes->data, recdes->length);
2875 
2876  if (or_get_oid (&buf, &this_oid) != NO_ERROR)
2877  {
2878  goto exit_on_error;
2879  }
2880  buf.ptr = PTR_ALIGN (buf.ptr, MAX_ALIGNMENT);
2881 
2882  /* Do not copy the string--just use the pointer. The pr_ routines for strings and sets have different semantics for
2883  * length. */
2884  if (TP_DOMAIN_TYPE (load_args->btid->key_type) == DB_TYPE_MIDXKEY)
2885  {
2886  key_size = buf.endptr - buf.ptr;
2887  }
2888 
2889  if ((*(load_args->btid->key_type->type->readval)) (&buf, &this_key, load_args->btid->key_type, key_size, copy, NULL,
2890  0) != NO_ERROR)
2891  {
2892  goto exit_on_error;
2893  }
2894 
2895  printf ("Attribute: ");
2896  btree_dump_key (stdout, &this_key);
2897  printf (" Volid: %d", this_oid.volid);
2898  printf (" Pageid: %d", this_oid.pageid);
2899  printf (" Slotid: %d\n", this_oid.slotid);
2900 
2901 end:
2902 
2903  copy = btree_clear_key_value (copy, &this_key);
2904 
2905  return ret;
2906 
2907 exit_on_error:
2908 
2909  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
2910 }
2911 #endif /* CUBRID_DEBUG */
2912 
2913 /*
2914  * btree_index_sort () - Sort for the index file creation
2915  * return: int
2916  * sort_args(in): sort arguments; specifies the sort-attribute as well as
2917  * the structure of the input objects
2918  * out_func(in): output function to utilize the sorted items as they are
2919  * produced
2920  * out_args(in): arguments to the out_func.
2921  *
2922  * Note: This function supports the initial loading phase of B+tree
2923  * indices by providing an ordered list of (index-attribute
2924  * value, object address) pairs. It uses the general sorting
2925  * facility provided in the "sr" module.
2926  */
2927 static int
2928 btree_index_sort (THREAD_ENTRY * thread_p, SORT_ARGS * sort_args, SORT_PUT_FUNC * out_func, void *out_args)
2929 {
2930  int i;
2931  bool includes_tde_class = false;
2932  TDE_ALGORITHM tde_algo = TDE_ALGORITHM_NONE;
2933 
2934  for (i = 0; i < sort_args->n_classes; i++)
2935  {
2936  if (heap_get_class_tde_algorithm (thread_p, &sort_args->class_ids[i], &tde_algo) != NO_ERROR)
2937  {
2938  return ER_FAILED;
2939  }
2940  if (tde_algo != TDE_ALGORITHM_NONE)
2941  {
2942  includes_tde_class = true;
2943  break;
2944  }
2945  }
2946 
2947  return sort_listfile (thread_p, sort_args->hfids[0].vfid.volid, 0 /* TODO - support parallelism */ ,
2948  &btree_sort_get_next, sort_args, out_func, out_args, compare_driver, sort_args, SORT_DUP,
2949  NO_SORT_LIMIT, includes_tde_class);
2950 }
2951 
2952 /*
2953  * btree_sort_get_next () - Get_key function for index sorting
2954  * return: SORT_STATUS
2955  * temp_recdes(in): temporary record descriptor; specifies where to put the
2956  * next sort item.
2957  * arg(in): sort arguments; provides information about how to produce
2958  * the next sort item.
2959  *
2960  * Note: This function is passed by the "btree_index_sort" function to
2961  * the "sort_listfile" function to obtain the value of the attribute
2962  * (on which the B+tree index for the class is to be created)
2963  * of each object successively.
2964  */
2965 static SORT_STATUS
2966 btree_sort_get_next (THREAD_ENTRY * thread_p, RECDES * temp_recdes, void *arg)
2967 {
2968  SCAN_CODE scan_result;
2969  DB_VALUE dbvalue;
2970  DB_VALUE *dbvalue_ptr;
2971  int key_len;
2972  OID prev_oid;
2974  OR_BUF buf;
2975  int value_has_null;
2976  int next_size;
2977  int record_size;
2978  int oid_size;
2979  char midxkey_buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_midxkey_buf;
2980  int *prefix_lengthp;
2981  int result;
2983  MVCC_SNAPSHOT mvcc_snapshot_dirty;
2984  MVCC_SATISFIES_SNAPSHOT_RESULT snapshot_dirty_satisfied;
2985 
2986  db_make_null (&dbvalue);
2987 
2988  aligned_midxkey_buf = PTR_ALIGN (midxkey_buf, MAX_ALIGNMENT);
2989 
2990  sort_args = (SORT_ARGS *) arg;
2991  prev_oid = sort_args->cur_oid;
2992 
2993  if (BTREE_IS_UNIQUE (sort_args->unique_pk))
2994  {
2995  oid_size = 2 * OR_OID_SIZE;
2996  }
2997  else
2998  {
2999  oid_size = OR_OID_SIZE;
3000  }
3001 
3002  mvcc_snapshot_dirty.snapshot_fnc = mvcc_satisfies_dirty;
3003 
3004  do
3005  { /* Infinite loop */
3006  int cur_class, attr_offset;
3007  bool save_cache_last_fix_page;
3008 
3009  /*
3010  * This infinite loop will be exited when a satisfactory next value is
3011  * found (i.e., when an object belonging to this class with a non-null
3012  * attribute value is found), or when there are no more objects in the
3013  * heap files.
3014  */
3015 
3016  /*
3017  * RETRIEVE THE NEXT OBJECT
3018  */
3019 
3020  cur_class = sort_args->cur_class;
3021  attr_offset = cur_class * sort_args->n_attrs;
3022  sort_args->in_recdes.data = NULL;
3023  scan_result =
3024  heap_next (thread_p, &sort_args->hfids[cur_class], &sort_args->class_ids[cur_class], &sort_args->cur_oid,
3025  &sort_args->in_recdes, &sort_args->hfscan_cache,
3026  sort_args->hfscan_cache.cache_last_fix_page ? PEEK : COPY);
3027 
3028  switch (scan_result)
3029  {
3030 
3031  case S_END:
3032  /* No more objects in this heap, finish the current scan */
3033  if (sort_args->attrinfo_inited)
3034  {
3035  heap_attrinfo_end (thread_p, &sort_args->attr_info);
3036  if (sort_args->filter)
3037  {
3038  heap_attrinfo_end (thread_p, sort_args->filter->cache_pred);
3039  }
3040  if (sort_args->func_index_info && sort_args->func_index_info->expr)
3041  {
3042  heap_attrinfo_end (thread_p, sort_args->func_index_info->expr->cache_attrinfo);
3043  }
3044  }
3045  sort_args->attrinfo_inited = 0;
3046  save_cache_last_fix_page = sort_args->hfscan_cache.cache_last_fix_page;
3047  if (sort_args->scancache_inited)
3048  {
3049  (void) heap_scancache_end (thread_p, &sort_args->hfscan_cache);
3050  }
3051  sort_args->scancache_inited = 0;
3052 
3053  /* Are we through with all the non-null heaps? */
3054  sort_args->cur_class++;
3055  while ((sort_args->cur_class < sort_args->n_classes)
3056  && HFID_IS_NULL (&sort_args->hfids[sort_args->cur_class]))
3057  {
3058  sort_args->cur_class++;
3059  }
3060 
3061  if (sort_args->cur_class == sort_args->n_classes)
3062  {
3063  return SORT_NOMORE_RECS;
3064  }
3065  else
3066  {
3067  /* start up the next scan */
3068  cur_class = sort_args->cur_class;
3069  attr_offset = cur_class * sort_args->n_attrs;
3070 
3071  if (heap_scancache_start (thread_p, &sort_args->hfscan_cache, &sort_args->hfids[cur_class],
3072  &sort_args->class_ids[cur_class], save_cache_last_fix_page, false,
3073  NULL) != NO_ERROR)
3074  {
3075  return SORT_ERROR_OCCURRED;
3076  }
3077  sort_args->scancache_inited = 1;
3078 
3079  if (heap_attrinfo_start (thread_p, &sort_args->class_ids[cur_class], sort_args->n_attrs,
3080  &sort_args->attr_ids[attr_offset], &sort_args->attr_info) != NO_ERROR)
3081  {
3082  return SORT_ERROR_OCCURRED;
3083  }
3084  sort_args->attrinfo_inited = 1;
3085 
3086  /* set the scan to the initial state for this new heap */
3087  OID_SET_NULL (&sort_args->cur_oid);
3088 
3090  {
3091  _er_log_debug (ARG_FILE_LINE, "DEBUG_BTREE: load start on class(%d, %d, %d), btid(%d, (%d, %d)).",
3092  sort_args->class_ids[sort_args->cur_class].volid,
3093  sort_args->class_ids[sort_args->cur_class].pageid,
3094  sort_args->class_ids[sort_args->cur_class].slotid,
3095  sort_args->btid->sys_btid->root_pageid, sort_args->btid->sys_btid->vfid.volid,
3096  sort_args->btid->sys_btid->vfid.fileid);
3097  }
3098  }
3099  continue;
3100 
3101  case S_ERROR:
3102  case S_DOESNT_EXIST:
3103  case S_DOESNT_FIT:
3106  return SORT_ERROR_OCCURRED;
3107 
3108  case S_SUCCESS:
3109  break;
3110  }
3111 
3112  /*
3113  * Produce the sort item for this object
3114  */
3115 
3116  /* filter out dead records before any more checks */
3117  if (or_mvcc_get_header (&sort_args->in_recdes, &mvcc_header) != NO_ERROR)
3118  {
3119  return SORT_ERROR_OCCURRED;
3120  }
3121  if (MVCC_IS_HEADER_DELID_VALID (&mvcc_header) && MVCC_GET_DELID (&mvcc_header) < sort_args->oldest_visible_mvccid)
3122  {
3123  continue;
3124  }
3125  if (MVCC_IS_HEADER_INSID_NOT_ALL_VISIBLE (&mvcc_header)
3126  && MVCC_GET_INSID (&mvcc_header) < sort_args->oldest_visible_mvccid)
3127  {
3128  /* Insert MVCCID is now visible to everyone. Clear it to avoid unnecessary vacuuming. */
3130  }
3131 
3132  snapshot_dirty_satisfied = mvcc_snapshot_dirty.snapshot_fnc (thread_p, &mvcc_header, &mvcc_snapshot_dirty);
3133 
3134  if (sort_args->filter)
3135  {
3136  if (heap_attrinfo_read_dbvalues (thread_p, &sort_args->cur_oid, &sort_args->in_recdes, NULL,
3137  sort_args->filter->cache_pred) != NO_ERROR)
3138  {
3139  return SORT_ERROR_OCCURRED;
3140  }
3141 
3142  result = (*sort_args->filter_eval_func) (thread_p, sort_args->filter->pred, NULL, &sort_args->cur_oid);
3143  if (result == V_ERROR)
3144  {
3145  return SORT_ERROR_OCCURRED;
3146  }
3147  else if (result != V_TRUE)
3148  {
3149  continue;
3150  }
3151  }
3152 
3153  if (sort_args->func_index_info && sort_args->func_index_info->expr)
3154  {
3155  if (snapshot_dirty_satisfied != SNAPSHOT_SATISFIED)
3156  {
3157  /* Check snapshot before key generation. Key generation may leads to errors when a function is involved. */
3158  continue;
3159  }
3160 
3161  if (heap_attrinfo_read_dbvalues (thread_p, &sort_args->cur_oid, &sort_args->in_recdes, NULL,
3162  sort_args->func_index_info->expr->cache_attrinfo) != NO_ERROR)
3163  {
3164  return SORT_ERROR_OCCURRED;
3165  }
3166  }
3167 
3168  if (sort_args->n_attrs == 1)
3169  { /* single-column index */
3170  if (heap_attrinfo_read_dbvalues (thread_p, &sort_args->cur_oid, &sort_args->in_recdes, NULL,
3171  &sort_args->attr_info) != NO_ERROR)
3172  {
3173  return SORT_ERROR_OCCURRED;
3174  }
3175  }
3176 
3177  prefix_lengthp = NULL;
3178  if (sort_args->attrs_prefix_length)
3179  {
3180  prefix_lengthp = &(sort_args->attrs_prefix_length[0]);
3181  }
3182 
3183  dbvalue_ptr =
3184  heap_attrinfo_generate_key (thread_p, sort_args->n_attrs, &sort_args->attr_ids[attr_offset], prefix_lengthp,
3185  &sort_args->attr_info, &sort_args->in_recdes, &dbvalue, aligned_midxkey_buf,
3186  sort_args->func_index_info, NULL);
3187  if (dbvalue_ptr == NULL)
3188  {
3189  return SORT_ERROR_OCCURRED;
3190  }
3191 
3192  value_has_null = 0; /* init */
3193  if (DB_IS_NULL (dbvalue_ptr) || btree_multicol_key_has_null (dbvalue_ptr))
3194  {
3195  value_has_null = 1; /* found null columns */
3196  }
3197 
3198  if (sort_args->not_null_flag && value_has_null && snapshot_dirty_satisfied == SNAPSHOT_SATISFIED)
3199  {
3200  if (dbvalue_ptr == &dbvalue || dbvalue_ptr->need_clear == true)
3201  {
3202  pr_clear_value (dbvalue_ptr);
3203  }
3204 
3206  return SORT_ERROR_OCCURRED;
3207  }
3208 
3209  if (DB_IS_NULL (dbvalue_ptr) || btree_multicol_key_is_null (dbvalue_ptr))
3210  {
3211  if (snapshot_dirty_satisfied == SNAPSHOT_SATISFIED)
3212  {
3213  /* All objects that were not candidates for vacuum are loaded, but statistics should only care for
3214  * objects that have not been deleted and committed at the time of load. */
3215  sort_args->n_oids++; /* Increment the OID counter */
3216  sort_args->n_nulls++; /* Increment the NULL counter */
3217  }
3218  if (dbvalue_ptr == &dbvalue || dbvalue_ptr->need_clear == true)
3219  {
3220  pr_clear_value (dbvalue_ptr);
3221  }
3223  {
3225  "DEBUG_BTREE: load sort found null at oid(%d, %d, %d)"
3226  ", class_oid(%d, %d, %d), btid(%d, (%d, %d).", sort_args->cur_oid.volid,
3227  sort_args->cur_oid.pageid, sort_args->cur_oid.slotid,
3228  sort_args->class_ids[sort_args->cur_class].volid,
3229  sort_args->class_ids[sort_args->cur_class].pageid,
3230  sort_args->class_ids[sort_args->cur_class].slotid, sort_args->btid->sys_btid->root_pageid,
3231  sort_args->btid->sys_btid->vfid.volid, sort_args->btid->sys_btid->vfid.fileid);
3232  }
3233  continue;
3234  }
3235 
3236  key_len = sort_args->key_type->type->get_disk_size_of_value (dbvalue_ptr);
3237 
3238  if (key_len > 0)
3239  {
3240  next_size = sizeof (char *);
3241  record_size = (next_size /* Pointer to next */
3242  + OR_INT_SIZE /* Has null */
3243  + oid_size /* OID, Class OID */
3244  + 2 * OR_MVCCID_SIZE /* Insert and delete MVCCID */
3245  + key_len /* Key length */
3246  + (int) MAX_ALIGNMENT /* Alignment */ );
3247 
3248  if (temp_recdes->area_size < record_size)
3249  {
3250  /*
3251  * Record is too big to fit into temp_recdes area; so
3252  * backtrack this iteration
3253  */
3254  sort_args->cur_oid = prev_oid;
3255  temp_recdes->length = record_size;
3256  goto nofit;
3257  }
3258 
3259  assert (PTR_ALIGN (temp_recdes->data, MAX_ALIGNMENT) == temp_recdes->data);
3260  or_init (&buf, temp_recdes->data, 0);
3261 
3262  or_pad (&buf, next_size); /* init as NULL */
3263 
3264  /* save has_null */
3265  if (or_put_byte (&buf, value_has_null) != NO_ERROR)
3266  {
3267  goto nofit;
3268  }
3269 
3270  or_advance (&buf, (OR_INT_SIZE - OR_BYTE_SIZE));
3271  assert (buf.ptr == PTR_ALIGN (buf.ptr, INT_ALIGNMENT));
3272 
3273  if (BTREE_IS_UNIQUE (sort_args->unique_pk))
3274  {
3275  if (or_put_oid (&buf, &sort_args->class_ids[cur_class]) != NO_ERROR)
3276  {
3277  goto nofit;
3278  }
3279  }
3280 
3281  if (or_put_oid (&buf, &sort_args->cur_oid) != NO_ERROR)
3282  {
3283  goto nofit;
3284  }
3285 
3286  /* Pack insert and delete MVCCID's */
3287  if (MVCC_IS_HEADER_INSID_NOT_ALL_VISIBLE (&mvcc_header))
3288  {
3289  if (or_put_mvccid (&buf, MVCC_GET_INSID (&mvcc_header)) != NO_ERROR)
3290  {
3291  goto nofit;
3292  }
3293  }
3294  else
3295  {
3296  if (or_put_mvccid (&buf, MVCCID_ALL_VISIBLE) != NO_ERROR)
3297  {
3298  goto nofit;
3299  }
3300  }
3301 
3302  if (MVCC_IS_HEADER_DELID_VALID (&mvcc_header))
3303  {
3304  if (or_put_mvccid (&buf, MVCC_GET_DELID (&mvcc_header)) != NO_ERROR)
3305  {
3306  goto nofit;
3307  }
3308  }
3309  else
3310  {
3311  if (or_put_mvccid (&buf, MVCCID_NULL) != NO_ERROR)
3312  {
3313  goto nofit;
3314  }
3315  }
3316 
3318  {
3320  "DEBUG_BTREE: load sort found oid(%d, %d, %d)"
3321  ", class_oid(%d, %d, %d), btid(%d, (%d, %d), mvcc_info=%llu | %llu.",
3322  sort_args->cur_oid.volid, sort_args->cur_oid.pageid, sort_args->cur_oid.slotid,
3323  sort_args->class_ids[sort_args->cur_class].volid,
3324  sort_args->class_ids[sort_args->cur_class].pageid,
3325  sort_args->class_ids[sort_args->cur_class].slotid, sort_args->btid->sys_btid->root_pageid,
3326  sort_args->btid->sys_btid->vfid.volid, sort_args->btid->sys_btid->vfid.fileid,
3327  MVCC_IS_FLAG_SET (&mvcc_header,
3328  OR_MVCC_FLAG_VALID_INSID) ? MVCC_GET_INSID (&mvcc_header) :
3329  MVCCID_ALL_VISIBLE, MVCC_IS_FLAG_SET (&mvcc_header,
3331  MVCC_GET_DELID (&mvcc_header) : MVCCID_NULL);
3332  }
3333 
3334  assert (buf.ptr == PTR_ALIGN (buf.ptr, INT_ALIGNMENT));
3335 
3336  if (sort_args->key_type->type->data_writeval (&buf, dbvalue_ptr) != NO_ERROR)
3337  {
3338  goto nofit;
3339  }
3340 
3341  temp_recdes->length = CAST_STRLEN (buf.ptr - buf.buffer);
3342 
3343  if (dbvalue_ptr == &dbvalue || dbvalue_ptr->need_clear == true)
3344  {
3345  pr_clear_value (dbvalue_ptr);
3346  }
3347  }
3348 
3349  if (snapshot_dirty_satisfied == SNAPSHOT_SATISFIED)
3350  {
3351  /* All objects that were not candidates for vacuum are loaded, but statistics should only care for objects
3352  * that have not been deleted and committed at the time of load. */
3353  sort_args->n_oids++; /* Increment the OID counter */
3354  }
3355 
3356  if (key_len > 0)
3357  {
3358  return SORT_SUCCESS;
3359  }
3360 
3361  }
3362  while (true);
3363 
3364 nofit:
3365 
3366  if (dbvalue_ptr == &dbvalue || dbvalue_ptr->need_clear == true)
3367  {
3368  pr_clear_value (dbvalue_ptr);
3369  }
3370 
3371  return SORT_REC_DOESNT_FIT;
3372 }
3373 
3374 /*
3375  * compare_driver () -
3376  * return:
3377  * first(in):
3378  * second(in):
3379  * arg(in):
3380  */
3381 static int
3382 compare_driver (const void *first, const void *second, void *arg)
3383 {
3384  char *mem1 = *(char **) first;
3385  char *mem2 = *(char **) second;
3386  int has_null;
3389  int c = DB_UNK;
3390 
3391  sort_args = (SORT_ARGS *) arg;
3392  key_type = sort_args->key_type;
3393 
3394  assert (PTR_ALIGN (mem1, MAX_ALIGNMENT) == mem1);
3395  assert (PTR_ALIGN (mem2, MAX_ALIGNMENT) == mem2);
3396 
3397  /* Skip next link */
3398  mem1 += sizeof (char *);
3399  mem2 += sizeof (char *);
3400 
3401  /* Read value_has_null */
3402  assert (OR_GET_BYTE (mem1) == 0 || OR_GET_BYTE (mem1) == 1);
3403  assert (OR_GET_BYTE (mem2) == 0 || OR_GET_BYTE (mem2) == 1);
3404  has_null = (OR_GET_BYTE (mem1) || OR_GET_BYTE (mem2)) ? 1 : 0;
3405 
3406  mem1 += OR_INT_SIZE;
3407  mem2 += OR_INT_SIZE;
3408 
3409  assert (PTR_ALIGN (mem1, INT_ALIGNMENT) == mem1);
3410  assert (PTR_ALIGN (mem2, INT_ALIGNMENT) == mem2);
3411 
3412  /* Skip the oids */
3413  if (BTREE_IS_UNIQUE (sort_args->unique_pk))
3414  { /* unique index */
3415  mem1 += (2 * OR_OID_SIZE);
3416  mem2 += (2 * OR_OID_SIZE);
3417  }
3418  else
3419  { /* non-unique index */
3420  mem1 += OR_OID_SIZE;
3421  mem2 += OR_OID_SIZE;
3422  }
3423 
3424  assert (PTR_ALIGN (mem1, INT_ALIGNMENT) == mem1);
3425  assert (PTR_ALIGN (mem2, INT_ALIGNMENT) == mem2);
3426 
3427  /* Skip the MVCCID's */
3428  mem1 += 2 * OR_MVCCID_SIZE;
3429  mem2 += 2 * OR_MVCCID_SIZE;
3430 
3431  assert (PTR_ALIGN (mem1, INT_ALIGNMENT) == mem1);
3432  assert (PTR_ALIGN (mem2, INT_ALIGNMENT) == mem2);
3433 
3434  if (TP_DOMAIN_TYPE (key_type) == DB_TYPE_MIDXKEY)
3435  {
3436  int i;
3437  char *bitptr1, *bitptr2;
3438  int bitmap_size;
3439  TP_DOMAIN *dom;
3440 
3441  /* fast implementation of pr_midxkey_compare (). do not use DB_VALUE container for speed-up */
3442 
3443  bitptr1 = mem1;
3444  bitptr2 = mem2;
3445 
3446  bitmap_size = OR_MULTI_BOUND_BIT_BYTES (key_type->precision);
3447 
3448  mem1 += bitmap_size;
3449  mem2 += bitmap_size;
3450 
3451 #if !defined(NDEBUG)
3452  for (i = 0, dom = key_type->setdomain; dom; dom = dom->next, i++);
3453  assert (i == key_type->precision);
3454 #endif
3455 
3456  if (sort_args->func_index_info != NULL)
3457  {
3458  assert (sort_args->n_attrs <= key_type->precision);
3459  }
3460  else
3461  {
3462  assert (sort_args->n_attrs == key_type->precision);
3463  }
3464  assert (key_type->setdomain != NULL);
3465 
3466  for (i = 0, dom = key_type->setdomain; i < key_type->precision && dom; i++, dom = dom->next)
3467  {
3468  /* val1 or val2 is NULL */
3469  if (has_null)
3470  {
3471  if (OR_MULTI_ATT_IS_UNBOUND (bitptr1, i))
3472  { /* element val is null? */
3473  if (OR_MULTI_ATT_IS_UNBOUND (bitptr2, i))
3474  {
3475  continue;
3476  }
3477 
3478  c = DB_LT;
3479  break; /* exit for-loop */
3480  }
3481  else if (OR_MULTI_ATT_IS_UNBOUND (bitptr2, i))
3482  {
3483  c = DB_GT;
3484  break; /* exit for-loop */
3485  }
3486  }
3487 
3488  /* check for val1 and val2 same domain */
3489  c = dom->type->index_cmpdisk (mem1, mem2, dom, 0, 1, NULL);
3490  assert (c == DB_LT || c == DB_EQ || c == DB_GT);
3491 
3492  if (c != DB_EQ)
3493  {
3494  break; /* exit for-loop */
3495  }
3496 
3497  mem1 += pr_midxkey_element_disk_size (mem1, dom);
3498  mem2 += pr_midxkey_element_disk_size (mem2, dom);
3499  } /* for (i = 0; ... ) */
3500  assert (c == DB_LT || c == DB_EQ || c == DB_GT);
3501 
3502  if (dom && dom->is_desc)
3503  {
3504  c = ((c == DB_GT) ? DB_LT : (c == DB_LT) ? DB_GT : c);
3505  }
3506  }
3507  else
3508  {
3509  OR_BUF buf_val1, buf_val2;
3510  DB_VALUE val1, val2;
3511 
3512  OR_BUF_INIT (buf_val1, mem1, -1);
3513  OR_BUF_INIT (buf_val2, mem2, -1);
3514 
3515  if (key_type->type->data_readval (&buf_val1, &val1, key_type, -1, false, NULL, 0) != NO_ERROR)
3516  {
3517  assert (false);
3518  return DB_UNK;
3519  }
3520 
3521  if (key_type->type->data_readval (&buf_val2, &val2, key_type, -1, false, NULL, 0) != NO_ERROR)
3522  {
3523  assert (false);
3524  return DB_UNK;
3525  }
3526 
3527  c = btree_compare_key (&val1, &val2, key_type, 0, 1, NULL);
3528 
3529  /* Clear the values if it is required */
3530  if (DB_NEED_CLEAR (&val1))
3531  {
3532  pr_clear_value (&val1);
3533  }
3534 
3535  if (DB_NEED_CLEAR (&val2))
3536  {
3537  pr_clear_value (&val2);
3538  }
3539  }
3540 
3541  assert (c == DB_LT || c == DB_EQ || c == DB_GT);
3542 
3543  /* compare OID for non-unique index */
3544  if (c == DB_EQ)
3545  {
3546  OID first_oid, second_oid;
3547 
3548  mem1 = *(char **) first;
3549  mem2 = *(char **) second;
3550 
3551  /* Skip next link */
3552  mem1 += sizeof (char *);
3553  mem2 += sizeof (char *);
3554 
3555  /* Skip value_has_null */
3556  mem1 += OR_INT_SIZE;
3557  mem2 += OR_INT_SIZE;
3558 
3559  if (BTREE_IS_UNIQUE (sort_args->unique_pk))
3560  {
3561  /* Skip class OID */
3562  mem1 += OR_OID_SIZE;
3563  mem2 += OR_OID_SIZE;
3564  }
3565 
3566  OR_GET_OID (mem1, &first_oid);
3567  OR_GET_OID (mem2, &second_oid);
3568 
3569  assert_release (!OID_EQ (&first_oid, &second_oid));
3570 
3571  if (OID_LT (&first_oid, &second_oid))
3572  {
3573  c = DB_LT;
3574  }
3575  else
3576  {
3577  c = DB_GT;
3578  }
3579  }
3580 
3581  return c;
3582 }
3583 
3584 /*
3585  * Linked list implementation
3586  */
3587 
3588 /*
3589  * list_add () -
3590  * return: NO_ERROR
3591  * list(in): which list to add
3592  * pageid(in): what value to put to the new node
3593  *
3594  * Note: This function adds a new node to the end of the given list.
3595  */
3596 static int
3597 list_add (BTREE_NODE ** list, VPID * pageid)
3598 {
3599  BTREE_NODE *new_node;
3600  BTREE_NODE *next_node;
3601  int ret = NO_ERROR;
3602 
3603  new_node = (BTREE_NODE *) os_malloc (sizeof (BTREE_NODE));
3604  if (new_node == NULL)
3605  {
3606  goto exit_on_error;
3607  }
3608 
3609  new_node->pageid = *pageid;
3610  new_node->next = NULL;
3611 
3612  if (*list == NULL)
3613  {
3614  *list = new_node;
3615  }
3616  else
3617  {
3618  next_node = *list;
3619  while (next_node->next != NULL)
3620  {
3621  next_node = next_node->next;
3622  }
3623 
3624  next_node->next = new_node;
3625  }
3626 
3627  return ret;
3628 
3629 exit_on_error:
3630 
3631  return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret;
3632 }
3633 
3634 /*
3635  * list_remove_first () -
3636  * return: nothing
3637  * list(in):
3638  *
3639  * Note: This function removes the first node of the given list (if it has one).
3640  */
3641 static void
3643 {
3644  BTREE_NODE *temp;
3645 
3646  if (*list != NULL)
3647  {
3648  temp = *list;
3649  *list = (*list)->next;
3650  os_free_and_init (temp);
3651  }
3652 }
3653 
3654 /*
3655  * list_clear () -
3656  * return: nothing
3657  * list(in):
3658  */
3659 static void
3661 {
3662  BTREE_NODE *p, *next;
3663 
3664  for (p = list; p != NULL; p = next)
3665  {
3666  next = p->next;
3667 
3668  os_free_and_init (p);
3669  }
3670 }
3671 
3672 /*
3673  * list_length () -
3674  * return: int
3675  * this_list(in): which list
3676  *
3677  * Note: This function returns the number of elements kept in the
3678  * given linked list.
3679  */
3680 static int
3681 list_length (const BTREE_NODE * this_list)
3682 {
3683  int length = 0;
3684 
3685  while (this_list != NULL)
3686  {
3687  length++;
3688  this_list = this_list->next;
3689  }
3690 
3691  return length;
3692 }
3693 
3694 #if defined(CUBRID_DEBUG)
3695 /*
3696  * list_print () -
3697  * return: this_list
3698  * this_list(in): which list to print
3699  *
3700  * Note: This function prints the elements of the given linked list;
3701  * It is used for debugging purposes.
3702  */
3703 static void
3704 list_print (const BTREE_NODE * this_list)
3705 {
3706  while (this_list != NULL)
3707  {
3708  (void) printf ("{%d, %d}n", this_list->pageid.volid, this_list->pageid.pageid);
3709  this_list = this_list->next;
3710  }
3711 }
3712 
3713 
3714 /*
3715  * btree_load_foo_debug () -
3716  * return:
3717  *
3718  * Note: To avoid warning during development
3719  */
3720 void
3721 btree_load_foo_debug (void)
3722 {
3723  (void) btree_dump_sort_output (NULL, NULL);
3724  list_print (NULL);
3725 }
3726 #endif /* CUBRID_DEBUG */
3727 
3728 /*
3729  * btree_rv_nodehdr_dump () - Dump node header recovery information
3730  * return: int
3731  * length(in): Length of Recovery Data
3732  * data(in): The data being logged
3733  *
3734  * Note: Dump node header recovery information
3735  */
3736 void
3737 btree_rv_nodehdr_dump (FILE * fp, int length, void *data)
3738 {
3739  BTREE_NODE_HEADER *header = NULL;
3740 
3741  header = (BTREE_NODE_HEADER *) data;
3742  assert (header != NULL);
3743 
3744  fprintf (fp, "\nNODE_TYPE: %s MAX_KEY_LEN: %4d PREV_PAGEID: {%4d , %4d} NEXT_PAGEID: {%4d , %4d} \n\n",
3745  header->node_level > 1 ? "NON_LEAF" : "LEAF", header->max_key_len, header->prev_vpid.volid,
3746  header->prev_vpid.pageid, header->next_vpid.volid, header->next_vpid.pageid);
3747 }
3748 
3749 /*
3750  * btree_node_number_of_keys () -
3751  * return: int
3752  *
3753  */
3754 int
3756 {
3757  int key_cnt;
3758 
3759  assert (page_ptr != NULL);
3760 #if !defined(NDEBUG)
3761  (void) pgbuf_check_page_ptype (thread_p, page_ptr, PAGE_BTREE);
3762 #endif
3763 
3764  key_cnt = spage_number_of_records (page_ptr) - 1;
3765 
3766 #if !defined(NDEBUG)
3767  {
3768  BTREE_NODE_HEADER *header = NULL;
3769  BTREE_NODE_TYPE node_type;
3770 
3771  header = btree_get_node_header (thread_p, page_ptr);
3772  if (header == NULL)
3773  {
3774  assert (false);
3775  }
3776 
3777  node_type = (header->node_level > 1) ? BTREE_NON_LEAF_NODE : BTREE_LEAF_NODE;
3778 
3779  if ((node_type == BTREE_NON_LEAF_NODE && key_cnt <= 0) || (node_type == BTREE_LEAF_NODE && key_cnt < 0))
3780  {
3781  er_log_debug (ARG_FILE_LINE, "btree_node_number_of_keys: node key count underflow: %d\n", key_cnt);
3782  assert (false);
3783  }
3784  }
3785 #endif
3786 
3787  assert_release (key_cnt >= 0);
3788 
3789  return key_cnt;
3790 }
3791 
3792 /*
3793  * btree_load_check_fk () - Checks if the current foreign key that needs to be loaded is passing all the requirements.
3794  *
3795  * return: NO_ERROR or error code.
3796  * load_args(in): Context for the loaded index (Includes leaf level of the foreign key)
3797  * sort_args(in): Context for sorting (Includes info on primary key)
3798  *
3799  */
3800 int
3801 btree_load_check_fk (THREAD_ENTRY * thread_p, const LOAD_ARGS * load_args, const SORT_ARGS * sort_args)
3802 {
3803  DB_VALUE fk_key, pk_key;
3804  bool clear_fk_key, clear_pk_key;
3805  int fk_node_key_cnt = -1, pk_node_key_cnt = -1;
3806  BTREE_NODE_HEADER *fk_node_header = NULL, *pk_node_header = NULL;
3807  VPID vpid;
3808  int ret = NO_ERROR, i;
3809  PAGE_PTR curr_fk_pageptr = NULL, old_page = NULL;
3810  INDX_SCAN_ID pk_isid;
3811  BTREE_SCAN pk_bt_scan;
3812  INT16 fk_slot_id = -1;
3813  bool found = false, pk_has_slot_visible = false, fk_has_visible = false;
3814  char *val_print = NULL;
3815  bool is_fk_scan_desc = false;
3816  MVCC_SNAPSHOT mvcc_snapshot_dirty;
3817  int lock_ret = LK_GRANTED;
3818  DB_VALUE_COMPARE_RESULT compare_ret;
3819  OR_CLASSREP *classrepr = NULL;
3820  int classrepr_cacheindex = -1, part_count = -1, pos = -1;
3821  bool clear_pcontext = false, has_partitions = false;
3822  PRUNING_CONTEXT pcontext;
3823  BTID pk_btid;
3824  OID pk_clsoid;
3825  HFID pk_dummy_hfid;
3826  BTREE_SCAN_PART partitions[MAX_PARTITIONS];
3827  bool has_nulls = false;
3828 
3829  btree_init_temp_key_value (&clear_fk_key, &fk_key);
3830  btree_init_temp_key_value (&clear_pk_key, &pk_key);
3831 
3832  mvcc_snapshot_dirty.snapshot_fnc = mvcc_satisfies_dirty;
3833 
3834  /* Initialize index scan on primary key btid. */
3835  scan_init_index_scan (&pk_isid, NULL, NULL);
3836  BTREE_INIT_SCAN (&pk_bt_scan);
3837 
3838  /* Lock the primary key class. */
3839  lock_ret = lock_object (thread_p, sort_args->fk_refcls_oid, oid_Root_class_oid, SIX_LOCK, LK_UNCOND_LOCK);
3840  if (lock_ret != LK_GRANTED)
3841  {
3842  ASSERT_ERROR_AND_SET (ret);
3843  goto end;
3844  }
3845 
3846  /* Get class info for the primary key */
3847  classrepr = heap_classrepr_get (thread_p, sort_args->fk_refcls_oid, NULL, NULL_REPRID, &classrepr_cacheindex);
3848  if (classrepr == NULL)
3849  {
3850  ret = ER_FK_INVALID;
3851  goto end;
3852  }
3853 
3854  /* Primary key index search prepare */
3855  ret = btree_prepare_bts (thread_p, &pk_bt_scan, sort_args->fk_refcls_pk_btid, &pk_isid, NULL, NULL, NULL, NULL,
3856  NULL, false, NULL);
3857  if (ret != NO_ERROR)
3858  {
3859  ASSERT_ERROR ();
3860  goto end;
3861  }
3862 
3863  /* Set the order. */
3864  is_fk_scan_desc = (sort_args->key_type->is_desc != pk_bt_scan.btid_int.key_type->is_desc);
3865 
3866  /* Get the corresponding leaf of the foreign key. */
3867  if (!is_fk_scan_desc)
3868  {
3869  /* Get first leaf vpid. */
3870  vpid = load_args->vpid_first_leaf;
3871  }
3872  else
3873  {
3874  /* Get the last leaf. Current leaf is the last one. */
3875  vpid = load_args->leaf.vpid;
3876  }
3877 
3878  /* Init slot id */
3879  pk_bt_scan.slot_id = 0;
3880 
3881  /* Check if there are any partitions on the primary key. */
3882  if (classrepr->has_partition_info > 0)
3883  {
3884  (void) partition_init_pruning_context (&pcontext);
3885  clear_pcontext = true;
3886 
3887  ret = partition_load_pruning_context (thread_p, sort_args->fk_refcls_oid, DB_PARTITIONED_CLASS, &pcontext);
3888  if (ret != NO_ERROR)
3889  {
3890  goto end;
3891  }
3892 
3893  /* Get number of partitions. */
3894  part_count = pcontext.count - 1; /* exclude partitioned table */
3895 
3896  assert (part_count <= MAX_PARTITIONS);
3897 
3898  /* Init context of each partition using the root context. */
3899  for (i = 0; i < part_count; i++)
3900  {
3901  memcpy (&partitions[i].pcontext, &pcontext, sizeof (PRUNING_CONTEXT));
3902  memcpy (&partitions[i].bt_scan, &pk_bt_scan, sizeof (BTREE_SCAN));
3903 
3904  partitions[i].bt_scan.btid_int.sys_btid = &partitions[i].btid;
3905  BTID_SET_NULL (&partitions[i].btid);
3906  partitions[i].header = NULL;
3907  partitions[i].key_cnt = -1;
3908  }
3909 
3910  has_partitions = true;
3911  }
3912 
3913  while (true)
3914  {
3915  ret = btree_advance_to_next_slot_and_fix_page (thread_p, sort_args->btid, &vpid, &curr_fk_pageptr, &fk_slot_id,
3916  &fk_key, &clear_fk_key, is_fk_scan_desc, &fk_node_key_cnt,
3917  &fk_node_header, &mvcc_snapshot_dirty);
3918  if (ret != NO_ERROR)
3919  {
3920  ASSERT_ERROR ();
3921  break;
3922  }
3923 
3924  has_nulls = false;
3925 
3926  if (curr_fk_pageptr == NULL)
3927  {
3928  /* Search has ended. */
3929  break;
3930  }
3931 
3932  if (DB_IS_NULL (&fk_key))
3933  {
3934  /* Only way to get this is by having no visible objects in the foreign key. */
3935  /* Must be checked!! */
3936  break;
3937  }
3938 
3939  /* Check for multi col nulls. */
3940  if (sort_args->n_attrs > 1)
3941  {
3942  has_nulls = btree_multicol_key_has_null (&fk_key);
3943  }
3944  else
3945  {
3946  /* TODO: unreachable case */
3947  has_nulls = DB_IS_NULL (&fk_key);
3948  }
3949 
3950  if (has_nulls)
3951  {
3952  /* ANSI SQL says
3953  *
3954  * The choices for <match type> are MATCH SIMPLE, MATCH PARTIAL, and MATCH FULL; MATCH SIMPLE is the default.
3955  * There is no semantic difference between these choices if there is only one referencing column (and, hence,
3956  * only one referenced column). There is also no semantic difference if all referencing columns are not
3957  * nullable. If there is more than one referencing column, at least one of which is nullable, and
3958  * if no <referencing period specification> is specified, then the various <match type>s have the following
3959  * semantics:
3960  *
3961  * MATCH SIMPLE: if at least one referencing column is null, then the row of the referencing table passes
3962  * the constraint check. If all referencing columns are not null, then the row passes the constraint check
3963  * if and only if there is a row of the referenced table that matches all the referencing columns.
3964  * MATCH PARTIAL: if all referencing columns are null, then the row of the referencing table passes
3965  * the constraint check. If at least one referencing columns is not null, then the row passes the constraint
3966  * check if and only if there is a row of the referenced table that matches all the non-null referencing
3967  * columns.
3968  * MATCH FULL: if all referencing columns are null, then the row of the referencing table passes
3969  * the constraint check. If all referencing columns are not null, then the row passes the constraint check
3970  * if and only if there is a row of the referenced table that matches all the referencing columns. If some
3971  * referencing column is null and another referencing column is non-null, then the row of the referencing
3972  * table violates the constraint check.
3973  *
3974  * In short, we don't provide options for <match type> and our behavior is <MATCH SIMPLE> which is
3975  * the default behavior of ANSI SQL and the other (commercial) products.
3976  */
3977 
3978  /* Skip current key. */
3979  continue;
3980  }
3981 
3982  /* We got the value from the foreign key, now search through the primary key index. */
3983  found = false;
3984 
3985  if (has_partitions)
3986  {
3987  COPY_OID (&pk_clsoid, sort_args->fk_refcls_oid);
3988  BTID_COPY (&pk_btid, sort_args->fk_refcls_pk_btid);
3989 
3990  /* Get the correct oid, btid and partition of the key we are looking for. */
3991  ret = partition_prune_partition_index (&pcontext, &fk_key, &pk_clsoid, &pk_btid, &pos);
3992  if (ret != NO_ERROR)
3993  {
3994  break;
3995  }
3996 
3997  if (BTID_IS_NULL (&partitions[pos].btid))
3998  {
3999  /* No need to lock individual partitions here, since the partitioned table is already locked */
4000  ret = partition_prune_unique_btid (&pcontext, &fk_key, &pk_clsoid, &pk_dummy_hfid, &pk_btid);
4001  if (ret != NO_ERROR)
4002  {
4003  break;
4004  }
4005 
4006  /* Update the partition BTID. */
4007  BTID_COPY (&partitions[pos].btid, &pk_btid);
4008  }
4009 
4010  /* Save the old page, if any. */
4011  if (pk_bt_scan.C_page != NULL)
4012  {
4013  old_page = pk_bt_scan.C_page;
4014  }
4015 
4016  /* Update references. */
4017  pk_bt_scan = partitions[pos].bt_scan;
4018  pk_node_key_cnt = partitions[pos].key_cnt;
4019  pk_node_header = partitions[pos].header;
4020  }
4021 
4022  /* Search through the primary key index. */
4023  if (pk_bt_scan.C_page == NULL)
4024  {
4025  /* No search has been initiated yet, we start from root. */
4026  ret = btree_locate_key (thread_p, &pk_bt_scan.btid_int, &fk_key, &pk_bt_scan.C_vpid, &pk_bt_scan.slot_id,
4027  &pk_bt_scan.C_page, &found);
4028  if (ret != NO_ERROR)
4029  {
4030  ASSERT_ERROR ();
4031  break;
4032  }
4033  else if (!found)
4034  {
4035  /* Value was not found at all, it means the foreign key is invalid. */
4036  val_print = pr_valstring (&fk_key);
4038  (val_print ? val_print : "unknown value"));
4039  ret = ER_FK_INVALID;
4040  db_private_free (thread_p, val_print);
4041  break;
4042  }
4043  else
4044  {
4045  /* First unfix the old page if applicable. The new page was fixed in btree_locate_key. */
4046  if (old_page != NULL)
4047  {
4048  pgbuf_unfix_and_init (thread_p, old_page);
4049  }
4050 
4051  /* Make sure there is at least one visible object. */
4052  ret = btree_is_slot_visible (thread_p, &pk_bt_scan.btid_int, pk_bt_scan.C_page, &mvcc_snapshot_dirty,
4053  pk_bt_scan.slot_id, &pk_has_slot_visible);
4054  if (ret != NO_ERROR)
4055  {
4056  break;
4057  }
4058 
4059  if (!pk_has_slot_visible)
4060  {
4061  /* No visible object in current page, but the key was located here. Should not happen often. */
4062  val_print = pr_valstring (&fk_key);
4064  (val_print ? val_print : "unknown value"));
4065  ret = ER_FK_INVALID;
4066  db_private_free (thread_p, val_print);
4067  break;
4068  }
4069 
4070  assert (pk_bt_scan.C_page != NULL);
4071  }
4072 
4073  /* Unfix old page, if any. */
4074  if (old_page != NULL)
4075  {
4076  pgbuf_unfix_and_init (thread_p, old_page);
4077  }
4078  }
4079  else
4080  {
4081  /* We try to resume the search in the current leaf. */
4082  while (!found)
4083  {
4084  ret = btree_advance_to_next_slot_and_fix_page (thread_p, &pk_bt_scan.btid_int, &pk_bt_scan.C_vpid,
4085  &pk_bt_scan.C_page, &pk_bt_scan.slot_id, &pk_key,
4086  &clear_pk_key, false, &pk_node_key_cnt, &pk_node_header,
4087  &mvcc_snapshot_dirty);
4088  if (ret != NO_ERROR)
4089  {
4090  goto end;
4091  }
4092 
4093  if (pk_bt_scan.C_page == NULL)
4094  {
4095  /* The primary key has ended, but the value from foreign key was not found. */
4096  /* Foreign key is invalid. Set error. */
4097  val_print = pr_valstring (&fk_key);
4099  (val_print ? val_print : "unknown value"));
4100  ret = ER_FK_INVALID;
4101  db_private_free (thread_p, val_print);
4102  goto end;
4103  }
4104 
4105  /* We need to compare the current value with the new value from the primary key. */
4106  compare_ret = btree_compare_key (&pk_key, &fk_key, pk_bt_scan.btid_int.key_type, 1, 1, NULL);
4107  if (compare_ret == DB_EQ)
4108  {
4109  /* Found value, stop searching in pk. */
4110  break;
4111  }
4112  else if (compare_ret == DB_LT)
4113  {
4114  /* No match yet. Advance in pk. */
4115  continue;
4116  }
4117  else
4118  {
4119  /* Fk is invalid. Set error. */
4120  val_print = pr_valstring (&fk_key);
4122  (val_print ? val_print : "unknown value"));
4123  ret = ER_FK_INVALID;
4124  db_private_free (thread_p, val_print);
4125  goto end;
4126  }
4127  }
4128 
4129  if (!found && pk_bt_scan.slot_id > pk_node_key_cnt)
4130  {
4131  old_page = pk_bt_scan.C_page;
4132  pk_bt_scan.C_page = NULL;
4133  }
4134  }
4135 
4136  if (has_partitions)
4137  {
4138  /* Update references. */
4139  partitions[pos].key_cnt = pk_node_key_cnt;
4140  partitions[pos].header = pk_node_header;
4141  }
4142 
4143  if (found == true)
4144  {
4145  btree_clear_key_value (&clear_fk_key, &fk_key);
4146  }
4147 
4148  btree_clear_key_value (&clear_pk_key, &pk_key);
4149  }
4150 
4151 end:
4152 
4153  if (has_partitions)
4154  {
4155  for (i = 0; i < part_count; i++)
4156  {
4157  if (partitions[i].bt_scan.C_page != NULL)
4158  {
4159  pgbuf_unfix_and_init (thread_p, partitions[i].bt_scan.C_page);
4160  }
4161  }
4162  }
4163 
4164  if (old_page != NULL)
4165  {
4166  pgbuf_unfix_and_init (thread_p, old_page);
4167  }
4168 
4169  if (curr_fk_pageptr != NULL)
4170  {
4171  pgbuf_unfix_and_init (thread_p, curr_fk_pageptr);
4172  }
4173 
4174  if (pk_bt_scan.C_page != NULL)
4175  {
4176  pgbuf_unfix_and_init (thread_p, pk_bt_scan.C_page);
4177  }
4178 
4179  btree_clear_key_value (&clear_fk_key, &fk_key);
4180  btree_clear_key_value (&clear_pk_key, &pk_key);
4181 
4182  if (clear_pcontext == true)
4183  {
4184  partition_clear_pruning_context (&pcontext);
4185  }
4186 
4187  if (classrepr != NULL)
4188  {
4189  heap_classrepr_free_and_init (classrepr, &classrepr_cacheindex);
4190  }
4191 
4192  return ret;
4193 }
4194 
4195 /*
4196  * btree_get_value_from_leaf_slot () -
4197  *
4198  * return: NO_ERROR or error code.
4199  * btid_int(in): The structure of the B-tree where the leaf resides.
4200  * leaf_ptr(in): The leaf where the value needs to be extracted from.
4201  * slot_id(in): The slot from where the value must be pulled.
4202  * key(out): The value requested.
4203  * clear_key(out): needs to clear key if set
4204  *
4205  */
4206 static int
4208  DB_VALUE * key, bool * clear_key)
4209 {
4210  LEAF_REC leaf;
4211  int first_key_offset = 0;
4212  RECDES record;
4213  int ret = NO_ERROR;
4214 
4215  if (spage_get_record (thread_p, leaf_ptr, slot_id, &record, PEEK) != S_SUCCESS)
4216  {
4217  assert_release (false);
4218  ret = ER_FAILED;
4219  return ret;
4220  }
4221 
4222  ret = btree_read_record (thread_p, btid_int, leaf_ptr, &record, key, &leaf, BTREE_LEAF_NODE, clear_key,
4223  &first_key_offset, PEEK_KEY_VALUE, NULL);
4224  if (ret != NO_ERROR)
4225  {
4226  ASSERT_ERROR ();
4227  return ret;
4228  }
4229 
4230  return ret;
4231 }
4232 
4233 /*
4234  * btree_advance_to_next_slot_and_fix_page () -
4235  *
4236  * return: NO_ERROR or error code
4237  * btid(in): B-tree structure
4238  * vpid(in/out): VPID of the current page
4239  * pg_ptr(in/out): Page pointer for the current page.
4240  * slot_id(in/out): Slot id of the current/next value.
4241  * key(out): Requested key.
4242  * clear_key(out): needs to clear key if set.
4243  * key_cnt(in/out): Number of keys in current page.
4244  * header(in/out): The header of the current page.
4245  * mvcc(in): Needed for visibility check.
4246  *
4247  * Note:
4248  * This function will advance to a next page without using conditional latches.
4249  * Therefore, if this is used for a descending scan, it might not work properly
4250  * unless concurrency is guaranteed.
4251  */
4252 static int
4254  INT16 * slot_id, DB_VALUE * key, bool * clear_key, bool is_desc, int *key_cnt,
4255  BTREE_NODE_HEADER ** header, MVCC_SNAPSHOT * mvcc)
4256 {
4257  int ret = NO_ERROR;
4258  VPID next_vpid;
4259  PAGE_PTR page = *pg_ptr;
4260  BTREE_NODE_HEADER *local_header = *header;
4261  bool is_slot_visible = false;
4262  PAGE_PTR old_page = NULL;
4263 
4264  /* Clear current key, if any. */
4265  if (!DB_IS_NULL (key))
4266  {
4267  pr_clear_value (key);
4268  }
4269 
4270  if (page == NULL)
4271  {
4272  page = pgbuf_fix (thread_p, vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
4273  if (page == NULL)
4274  {
4275  ASSERT_ERROR_AND_SET (ret);
4276  return ret;
4277  }
4278 
4279  *slot_id = -1;
4280  }
4281 
4282  assert (page != NULL);
4283 
4284  /* Check page. */
4285  (void) pgbuf_check_page_ptype (thread_p, page, PAGE_BTREE);
4286 
4287  if (local_header == NULL)
4288  {
4289  /* Get the header of the page. */
4290  local_header = btree_get_node_header (thread_p, page);
4291  }
4292 
4293  if (*key_cnt == -1)
4294  {
4295  /* Get number of keys in page. */
4296  *key_cnt = btree_node_number_of_keys (thread_p, page);
4297  }
4298 
4299  /* If it is the first search. */
4300  if (*slot_id == -1)
4301  {
4302  *slot_id = is_desc ? (*key_cnt + 1) : 0;
4303  }
4304 
4305  /* Advance to next key. */
4306  while (true)
4307  {
4308  *slot_id += (is_desc ? -1 : 1);
4309  assert (0 <= *slot_id);
4310 
4311  if (*slot_id == 0 || *slot_id >= *key_cnt + 1)
4312  {
4313  next_vpid = is_desc ? local_header->prev_vpid : local_header->next_vpid;
4314  if (VPID_ISNULL (&next_vpid))
4315  {
4316  /* No next page. unfix current one. */
4317  pgbuf_unfix_and_init (thread_p, page);
4318  break;
4319  }
4320  else
4321  {
4322  old_page = page;
4323  page = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
4324  if (page == NULL)
4325  {
4326  ASSERT_ERROR_AND_SET (ret);
4327  return ret;
4328  }
4329 
4330  /* unfix old page */
4331  pgbuf_unfix_and_init (thread_p, old_page);
4332 
4333  *slot_id = is_desc ? *key_cnt : 1;
4334 
4335  /* Get the new header. */
4336  local_header = btree_get_node_header (thread_p, page);
4337 
4338  /* Get number of keys in new page. */
4339  *key_cnt = btree_node_number_of_keys (thread_p, page);
4340  }
4341  }
4342 
4343  if (mvcc != NULL)
4344  {
4345  ret = btree_is_slot_visible (thread_p, btid, page, mvcc, *slot_id, &is_slot_visible);
4346  if (ret != NO_ERROR)
4347  {
4348  return ret;
4349  }
4350 
4351  if (!is_slot_visible)
4352  {
4353  continue;
4354  }
4355  }
4356 
4357  /* The slot is visible. Fall through and get the key. */
4358  break;
4359  }
4360 
4361  if (page != NULL)
4362  {
4363  ret = btree_get_value_from_leaf_slot (thread_p, btid, page, *slot_id, key, clear_key);
4364  }
4365 
4366  *header = local_header;
4367  *pg_ptr = page;
4368 
4369  return ret;
4370 }
4371 
4372 /*
4373  * btree_is_slot_visible(): States if current slot is visible or not.
4374  *
4375  * thread_p(in): Thread entry.
4376  * btid(in): B-tree info.
4377  * pg_ptr(in): Page pointer.
4378  * mvcc_snapshot(in): The MVCC snapshot.
4379  * slot_id(in) : Slot id to be looked for.
4380  * is_visible(out): True or False
4381  *
4382  * return: error code if any error occurs.
4383  */
4384 static int
4386  int slot_id, bool * is_visible)
4387 {
4388  RECDES record;
4389  LEAF_REC leaf;
4390  int num_visible = 0;
4391  int key_offset = 0;
4392  int ret = NO_ERROR;
4393  bool dummy_clear_key;
4394 
4395  *is_visible = false;
4396 
4397  if (mvcc_snapshot == NULL)
4398  {
4399  /* Early out. */
4400  *is_visible = true;
4401  return ret;
4402  }
4403 
4404  /* Get the record. */
4405  if (spage_get_record (thread_p, pg_ptr, slot_id, &record, PEEK) != S_SUCCESS)
4406  {
4407  assert_release (false);
4408  ret = ER_FAILED;
4409  return ret;
4410  }
4411 
4412  /* Read the record. - no need of actual key value */
4413  ret = btree_read_record (thread_p, btid, pg_ptr, &record, NULL, &leaf, BTREE_LEAF_NODE, &dummy_clear_key,
4414  &key_offset, PEEK_KEY_VALUE, NULL);
4415  if (ret != NO_ERROR)
4416  {
4417  ASSERT_ERROR ();
4418  return ret;
4419  }
4420 
4421  /* Get the number of visible items. */
4422  ret = btree_get_num_visible_from_leaf_and_ovf (thread_p, btid, &record, key_offset, &leaf, NULL, mvcc_snapshot,
4423  &num_visible);
4424  if (ret != NO_ERROR)
4425  {
4426  return ret;
4427  }
4428 
4429  if (num_visible > 0)
4430  {
4431  *is_visible = true;
4432  }
4433 
4434  return ret;
4435 }
4436 
4437 BTID *
4438 xbtree_load_online_index (THREAD_ENTRY * thread_p, BTID * btid, const char *bt_name, TP_DOMAIN * key_type,
4439  OID * class_oids, int n_classes, int n_attrs, int *attr_ids, int *attrs_prefix_length,
4441  const char *fk_name, char *pred_stream, int pred_stream_size, char *func_pred_stream,
4442  int func_pred_stream_size, int func_col_id, int func_attr_index_start, int ib_thread_count)
4443 {
4444  int cur_class, attr_offset;
4446  PRED_EXPR_WITH_CONTEXT *filter_pred = NULL;
4448  DB_TYPE single_node_type = DB_TYPE_NULL;
4449  XASL_UNPACK_INFO *func_unpack_info = NULL;
4450  bool is_sysop_started = false;
4451  MVCC_SNAPSHOT *builder_snapshot = NULL;
4452  HEAP_SCANCACHE scan_cache;
4454  int ret = NO_ERROR;
4455  LOCK old_lock = SCH_M_LOCK;
4456  LOCK new_lock = IX_LOCK;
4457  bool scan_cache_inited = false;
4458  bool attr_info_inited = false;
4459  LOG_TDES *tdes;
4460  int lock_ret;
4461  BTID *list_btid = NULL;
4462  int old_wait_msec;
4463  bool old_check_intr;
4464 
4465  func_index_info.expr = NULL;
4466 
4467  /* Check for robustness */
4468  if (!btid || !hfids || !class_oids || !attr_ids || !key_type)
4469  {
4471  return NULL;
4472  }
4473 
4474  btid_int.sys_btid = btid;
4475  btid_int.unique_pk = unique_pk;
4476 
4477 #if !defined(NDEBUG)
4478  if (unique_pk)
4479  {
4480  assert (BTREE_IS_UNIQUE (btid_int.unique_pk));
4482  }
4483 #endif
4484 
4485  btid_int.key_type = key_type;
4486  VFID_SET_NULL (&btid_int.ovfid);
4488  COPY_OID (&btid_int.topclass_oid, &class_oids[0]);
4489  /*
4490  * for btree_range_search, part_key_desc is re-set at btree_initialize_bts
4491  */
4492  btid_int.part_key_desc = 0;
4493 
4494  /* init index key copy_buf info */
4495  btid_int.copy_buf = NULL;
4496  btid_int.copy_buf_len = 0;
4497  btid_int.nonleaf_key_type = btree_generate_prefix_domain (&btid_int);
4498 
4499  /* After building index acquire lock on table, the transaction has deadlock priority */
4500  tdes = LOG_FIND_CURRENT_TDES (thread_p);
4501  if (tdes)
4502  {
4503  tdes->has_deadlock_priority = true;
4504  }
4505 
4506  /* Acquire snapshot!! */
4507  builder_snapshot = logtb_get_mvcc_snapshot (thread_p);
4508  if (builder_snapshot == NULL)
4509  {
4510  goto error;
4511  }
4512 
4513  /* Alloc memory for btid list for unique indexes. */
4514  if (BTREE_IS_UNIQUE (unique_pk))
4515  {
4516  list_btid = (BTID *) malloc (n_classes * sizeof (BTID));
4517  if (list_btid == NULL)
4518  {
4521  goto error;
4522  }
4523  }
4524 
4525  /* Demote the locks for classes on which we want to load indices. */
4526  for (cur_class = 0; cur_class < n_classes; cur_class++)
4527  {
4528  ret = lock_demote_class_lock (thread_p, &class_oids[cur_class], new_lock, &old_lock);
4529  if (ret != NO_ERROR)
4530  {
4531  goto error;
4532  }
4533  }
4534 
4535  for (cur_class = 0; cur_class < n_classes; cur_class++)
4536  {
4537  /* Reinitialize filter and function for each class, if is the case. This is needed in order to bring the regu
4538  * variables in same state like initial state. Clearing XASL does not bring the regu variables in initial state.
4539  * A issue is clearing the cache (see cache_dbvalp and cache_attrinfo).
4540  * We may have the option to try to correct clearing XASL (to have initial state) or destroy it and reinitalize it.
4541  * For now, we choose reinitialization, since is much simply, and is used also in non-online case.
4542  */
4543  if (pred_stream && pred_stream_size > 0)
4544  {
4545  if (stx_map_stream_to_filter_pred (thread_p, &filter_pred, pred_stream, pred_stream_size) != NO_ERROR)
4546  {
4547  goto error;
4548  }
4549  }
4550 
4551  if (func_pred_stream && func_pred_stream_size > 0)
4552  {
4553  func_index_info.expr_stream = func_pred_stream;
4554  func_index_info.expr_stream_size = func_pred_stream_size;
4555  func_index_info.col_id = func_col_id;
4556  func_index_info.attr_index_start = func_attr_index_start;
4557  func_index_info.expr = NULL;
4558  if (stx_map_stream_to_func_pred (thread_p, &func_index_info.expr, func_pred_stream,
4559  func_pred_stream_size, &func_unpack_info))
4560  {
4561  goto error;
4562  }
4563  }
4564 
4565  attr_offset = cur_class * n_attrs;
4566 
4567  /* Start scancache */
4568  if (heap_scancache_start (thread_p, &scan_cache, &hfids[cur_class], &class_oids[cur_class], true, false,
4569  NULL) != NO_ERROR)
4570  {
4571  goto error;
4572  }
4573  scan_cache_inited = true;
4574 
4575  if (heap_attrinfo_start (thread_p, &class_oids[cur_class], n_attrs, &attr_ids[attr_offset], &attr_info) !=
4576  NO_ERROR)
4577  {
4578  goto error;
4579  }
4580  attr_info_inited = true;
4581 
4582  if (filter_pred != NULL)
4583  {
4584  if (heap_attrinfo_start (thread_p, &class_oids[cur_class], filter_pred->num_attrs_pred,
4585  filter_pred->attrids_pred, filter_pred->cache_pred) != NO_ERROR)
4586  {
4587  goto error;
4588  }
4589  }
4590 
4591  if (func_index_info.expr != NULL)
4592  {
4593  if (heap_attrinfo_start (thread_p, &class_oids[cur_class], n_attrs, &attr_ids[attr_offset],
4594  func_index_info.expr->cache_attrinfo) != NO_ERROR)
4595  {
4596  goto error;
4597  }
4598  }
4599 
4600  /* Assign the snapshot to the scan_cache. */
4601  scan_cache.mvcc_snapshot = builder_snapshot;
4602 
4603  ret = heap_get_btid_from_index_name (thread_p, &class_oids[cur_class], bt_name, btid_int.sys_btid);
4604  if (ret != NO_ERROR)
4605  {
4606  ASSERT_ERROR ();
4607  break;
4608  }
4609 
4610  /* For unique indices add to the list of btids for unique constraint checks. */
4611  if (BTREE_IS_UNIQUE (unique_pk))
4612  {
4613  list_btid[cur_class].root_pageid = btid_int.sys_btid->root_pageid;
4614  list_btid[cur_class].vfid.fileid = btid_int.sys_btid->vfid.fileid;
4615  list_btid[cur_class].vfid.volid = btid_int.sys_btid->vfid.volid;
4616  }
4617 
4619  {
4620  _er_log_debug (ARG_FILE_LINE, "DEBUG_BTREE: load start on class(%d, %d, %d), btid(%d, (%d, %d)).",
4621  OID_AS_ARGS (&class_oids[cur_class]), BTID_AS_ARGS (btid_int.sys_btid));
4622  }
4623 
4624  /* Start the online index builder. */
4625  ret = online_index_builder (thread_p, &btid_int, &hfids[cur_class], &class_oids[cur_class], n_classes, attr_ids,
4626  n_attrs, func_index_info, filter_pred, attrs_prefix_length, &attr_info, &scan_cache,
4627  unique_pk, ib_thread_count, key_type);
4628  if (ret != NO_ERROR)
4629  {
4630  break;
4631  }
4632 
4633  if (attr_info_inited)
4634  {
4635  heap_attrinfo_end (thread_p, &attr_info);
4636 
4637  if (filter_pred)
4638  {
4639  heap_attrinfo_end (thread_p, filter_pred->cache_pred);
4640  }
4641  if (func_index_info.expr)
4642  {
4643  heap_attrinfo_end (thread_p, func_index_info.expr->cache_attrinfo);
4644  }
4645 
4646  attr_info_inited = false;
4647  }
4648 
4649  if (scan_cache_inited)
4650  {
4651  heap_scancache_end (thread_p, &scan_cache);
4652  scan_cache_inited = false;
4653  }
4654 
4655  if (filter_pred != NULL)
4656  {
4657  /* to clear db values from dbvalue regu variable */
4658  qexec_clear_pred_context (thread_p, filter_pred, true);
4659 
4660  if (filter_pred->unpack_info != NULL)
4661  {
4662  free_xasl_unpack_info (thread_p, filter_pred->unpack_info);
4663  }
4664  db_private_free_and_init (thread_p, filter_pred);
4665  }
4666 
4667  if (func_index_info.expr != NULL)
4668  {
4669  (void) qexec_clear_func_pred (thread_p, func_index_info.expr);
4670  func_index_info.expr = NULL;
4671  }
4672 
4673  if (func_unpack_info != NULL)
4674  {
4675  free_xasl_unpack_info (thread_p, func_unpack_info);
4676  }
4677  }
4678 
4679  // We should recover the lock regardless of return code from online_index_builder.
4680  // Otherwise, we might be doomed to failure to abort the transaction.
4681  // We are going to do best to avoid lock promotion errors such as timeout and deadlocked.
4682 
4683  // never give up
4684  old_wait_msec = xlogtb_reset_wait_msecs (thread_p, LK_INFINITE_WAIT);
4685  old_check_intr = logtb_set_check_interrupt (thread_p, false);
4686 
4687  for (cur_class = 0; cur_class < n_classes; cur_class++)
4688  {
4689  /* Promote the lock to SCH_M_LOCK */
4690  /* we need to do this in a loop to retry in case of interruption */
4691  while (true)
4692  {
4693  lock_ret = lock_object (thread_p, &class_oids[cur_class], oid_Root_class_oid, SCH_M_LOCK, LK_UNCOND_LOCK);
4694  if (lock_ret == LK_GRANTED)
4695  {
4696  break;
4697  }
4698 #if defined (SERVER_MODE)
4699  else if (lock_ret == LK_NOTGRANTED_DUE_ERROR)
4700  {
4701  if (er_errid () == ER_INTERRUPTED)
4702  {
4703  // interruptions cannot be allowed here; lock must be promoted to either commit or rollback changes
4704  er_clear ();
4705  // make sure the transaction interrupt flag is cleared
4706  logtb_set_tran_index_interrupt (thread_p, thread_p->tran_index, false);
4707  // and retry
4708  continue;
4709  }
4710  }
4711  else if (lock_ret == LK_NOTGRANTED_DUE_TIMEOUT && css_is_shutdowning_server ())
4712  {
4713  // server shutdown forced timeout; but consistency requires that we get the lock upgrade no matter what
4714  er_clear ();
4715  continue;
4716  }
4717 #endif // SERVER_MODE
4718 
4719  // it is neither expected nor acceptable.
4720  assert (0);
4721  }
4722  }
4723 
4724  // reset back
4725  (void) xlogtb_reset_wait_msecs (thread_p, old_wait_msec);
4726  (void) logtb_set_check_interrupt (thread_p, old_check_intr);
4727 
4728  if (ret != NO_ERROR)
4729  {
4730  ASSERT_ERROR ();
4731  goto error;
4732  }
4733 
4734  if (BTREE_IS_UNIQUE (unique_pk))
4735  {
4736  for (cur_class = 0; cur_class < n_classes; cur_class++)
4737  {
4738  /* Check if we have a unique constraint violation for unique indexes. */
4739  ret =
4740  btree_online_index_check_unique_constraint (thread_p, &list_btid[cur_class], bt_name,
4741  &class_oids[cur_class]);
4742  if (ret != NO_ERROR)
4743  {
4744  ASSERT_ERROR ();
4745  btid = NULL;
4746  goto error;
4747  }
4748  }
4749  }
4750 
4751  assert (scan_cache_inited == false && attr_info_inited == false);
4752 
4753  if (list_btid != NULL)
4754  {
4755  free (list_btid);
4756  list_btid = NULL;
4757  }
4758 
4759  logpb_force_flush_pages (thread_p);
4760 
4761  /* TODO: Is this all right? */
4762  /* Invalidate snapshot. */
4763  if (builder_snapshot != NULL)
4764  {
4765  logtb_invalidate_snapshot_data (thread_p);
4766  }
4767 
4768  return btid;
4769 
4770 error:
4771  if (attr_info_inited)
4772  {
4773  heap_attrinfo_end (thread_p, &attr_info);
4774 
4775  if (filter_pred)
4776  {
4777  heap_attrinfo_end (thread_p, filter_pred->cache_pred);
4778  }
4779  if (func_index_info.expr)
4780  {
4781  heap_attrinfo_end (thread_p, func_index_info.expr->cache_attrinfo);
4782  }
4783 
4784  attr_info_inited = false;
4785  }
4786 
4787  if (scan_cache_inited)
4788  {
4789  heap_scancache_end (thread_p, &scan_cache);
4790  scan_cache_inited = false;
4791  }
4792 
4793  if (filter_pred != NULL)
4794  {
4795  /* to clear db values from dbvalue regu variable */
4796  qexec_clear_pred_context (thread_p, filter_pred, true);
4797 
4798  if (filter_pred->unpack_info != NULL)
4799  {
4800  free_xasl_unpack_info (thread_p, filter_pred->unpack_info);
4801  }
4802  db_private_free_and_init (thread_p, filter_pred);
4803  }
4804 
4805  if (func_index_info.expr != NULL)
4806  {
4807  (void) qexec_clear_func_pred (thread_p, func_index_info.expr);
4808  }
4809 
4810  if (func_unpack_info != NULL)
4811  {
4812  free_xasl_unpack_info (thread_p, func_unpack_info);
4813  }
4814 
4815  if (list_btid != NULL)
4816  {
4817  free (list_btid);
4818  }
4819 
4820  /* Invalidate snapshot. */
4821  if (builder_snapshot != NULL)
4822  {
4823  logtb_invalidate_snapshot_data (thread_p);
4824  }
4825 
4826  return NULL;
4827 }
4828 
4829 // *INDENT-OFF*
4830 static int
4832  int *attrids, int n_attrs, FUNCTION_INDEX_INFO func_idx_info,
4834  HEAP_SCANCACHE * scancache, int unique_pk, int ib_thread_count, TP_DOMAIN * key_type)
4835 {
4836  int ret = NO_ERROR, eval_res;
4837  OID cur_oid;
4838  RECDES cur_record;
4839  int cur_class;
4840  SCAN_CODE sc;
4841  FUNCTION_INDEX_INFO *p_func_idx_info;
4842  PR_EVAL_FNC filter_eval_fnc;
4843  DB_TYPE single_node_type = DB_TYPE_NULL;
4844  int attr_offset;
4845  DB_VALUE *p_dbvalue;
4846  int *p_prefix_length;
4847  uint64_t tasks_started = 0;
4848  char midxkey_buf[DBVAL_BUFSIZE + MAX_ALIGNMENT], *aligned_midxkey_buf;
4849  index_builder_loader_context load_context;
4850  bool is_parallel = ib_thread_count > 0;
4851  std::atomic<int> num_keys = {0}, num_oids = {0}, num_nulls = {0};
4852 
4853  std::unique_ptr<index_builder_loader_task> load_task = NULL;
4854 
4855  // a worker pool is built only of loading is done in parallel
4856  cubthread::entry_workpool *ib_workpool =
4857  is_parallel ?
4858  thread_get_manager()->create_worker_pool (ib_thread_count, 32, "Online index loader pool", &load_context, 1,
4860  : NULL;
4861 
4862  aligned_midxkey_buf = PTR_ALIGN (midxkey_buf, MAX_ALIGNMENT);
4863  p_func_idx_info = func_idx_info.expr ? &func_idx_info : NULL;
4864  filter_eval_fnc = (filter_pred != NULL) ? eval_fnc (thread_p, filter_pred->pred, &single_node_type) : NULL;
4865 
4866  /* Get the first entry from heap. */
4867  cur_class = 0;
4868  OID_SET_NULL (&cur_oid);
4869  cur_oid.volid = hfids[cur_class].vfid.volid;
4870 
4871  /* Do not let the page fixed after an extract. */
4872  scancache->cache_last_fix_page = false;
4873 
4874  load_context.m_has_error = false;
4875  load_context.m_error_code = NO_ERROR;
4876  load_context.m_tasks_executed = 0UL;
4877  load_context.m_key_type = key_type;
4878  load_context.m_conn = thread_p->conn_entry;
4879 
4880  PERF_UTIME_TRACKER time_online_index = PERF_UTIME_TRACKER_INITIALIZER;
4881 
4882  PERF_UTIME_TRACKER_START (thread_p, &time_online_index);
4883 
4884  /* Start extracting from heap. */
4885  for (;;)
4886  {
4887  DB_VALUE dbvalue;
4888 
4889  db_make_null (&dbvalue);
4890 
4891  /* Scan from heap and insert into the index. */
4892  attr_offset = cur_class * n_attrs;
4893 
4894  cur_record.data = NULL;
4895 
4896  sc = heap_next (thread_p, &hfids[cur_class], &class_oids[cur_class], &cur_oid, &cur_record, scancache, COPY);
4897  if (sc == S_ERROR)
4898  {
4899  ASSERT_ERROR_AND_SET (ret);
4900  break;
4901  }
4902  else if (sc == S_END)
4903  {
4904  break;
4905  }
4906 
4907  /* Make sure the scan was a success. */
4908  assert (sc == S_SUCCESS);
4909  assert (!OID_ISNULL (&cur_oid));
4910 
4911  if (filter_pred)
4912  {
4913  ret = heap_attrinfo_read_dbvalues (thread_p, &cur_oid, &cur_record, NULL, filter_pred->cache_pred);
4914  if (ret != NO_ERROR)
4915  {
4916  break;
4917  }
4918 
4919  eval_res = (*filter_eval_fnc) (thread_p, filter_pred->pred, NULL, &cur_oid);
4920  if (eval_res == V_ERROR)
4921  {
4922  ret = ER_FAILED;
4923  break;
4924  }
4925  else if (eval_res != V_TRUE)
4926  {
4927  continue;
4928  }
4929  }
4930 
4931  if (p_func_idx_info && p_func_idx_info->expr)
4932  {
4933  ret = heap_attrinfo_read_dbvalues (thread_p, &cur_oid, &cur_record, NULL,
4934  p_func_idx_info->expr->cache_attrinfo);
4935  if (ret != NO_ERROR)
4936  {
4937  break;
4938  }
4939  }
4940 
4941  if (n_attrs == 1)
4942  {
4943  /* Single column index. */
4944  ret = heap_attrinfo_read_dbvalues (thread_p, &cur_oid, &cur_record, NULL, attr_info);
4945  if (ret != NO_ERROR)
4946  {
4947  break;
4948  }
4949  }
4950 
4951  p_prefix_length = NULL;
4952  if (attrs_prefix_length)
4953  {
4954  p_prefix_length = &(attrs_prefix_length[0]);
4955  }
4956 
4957  /* Generate the key : provide key_type domain - needed for compares during sort */
4958  p_dbvalue = heap_attrinfo_generate_key (thread_p, n_attrs, &attrids[attr_offset], p_prefix_length, attr_info,
4959  &cur_record, &dbvalue, aligned_midxkey_buf, p_func_idx_info, key_type);
4960  if (p_dbvalue == NULL)
4961  {
4962  ret = ER_FAILED;
4963  break;
4964  }
4965 
4966  /* Dispatch the insert operation */
4967  if (load_task == NULL)
4968  {
4969  // create a new task
4970  load_task.reset (new index_builder_loader_task (btid_int->sys_btid, &class_oids[cur_class], unique_pk,
4971  load_context, num_keys, num_oids, num_nulls));
4972  }
4973  if (load_task->add_key (p_dbvalue, cur_oid) == index_builder_loader_task::BATCH_FULL)
4974  {
4975  // send task to worker pool for execution
4976  thread_get_manager ()->push_task (ib_workpool, load_task.release ());
4977  /* Increment tasks started. */
4978  tasks_started++;
4979  }
4980 
4981  /* Clear index key. */
4982  pr_clear_value (p_dbvalue);
4983 
4984  /* Check for possible errors. */
4985  if (load_context.m_has_error)
4986  {
4987  /* Also stop all threads. */
4989  ret = load_context.m_error_code;
4990  break;
4991  }
4992  }
4993 
4994  /* Check if the worker pool is empty */
4995  if (ret == NO_ERROR)
4996  {
4997  if (load_task != NULL && load_task->has_keys ())
4998  {
4999  // one last task
5000  thread_get_manager ()->push_task (ib_workpool, load_task.release ());
5001  /* Increment tasks started. */
5002  tasks_started++;
5003  }
5004  do
5005  {
5006  bool dummy_continue_checking = true;
5007 
5008  if (load_context.m_has_error != NO_ERROR)
5009  {
5010  /* Also stop all threads. */
5012  ret = load_context.m_error_code;
5013  break;
5014  }
5015 
5016  /* Wait for threads to finish. */
5017  thread_sleep (10);
5018 
5019  /* Check for interrupts. */
5020  if (logtb_is_interrupted (thread_p, true, &dummy_continue_checking))
5021  {
5023  ret = ER_INTERRUPTED;
5024  break;
5025  }
5026  }
5027  while (load_context.m_tasks_executed != tasks_started);
5028  }
5029 
5030  PERF_UTIME_TRACKER_TIME (thread_p, &time_online_index, PSTAT_BT_ONLINE_LOAD);
5031 
5032  thread_get_manager ()->destroy_worker_pool (ib_workpool);
5033 
5034  if (BTREE_IS_UNIQUE (btid_int->unique_pk))
5035  {
5036  logtb_tran_update_btid_unique_stats (thread_p, btid_int->sys_btid, num_keys, num_oids, num_nulls);
5037  }
5038 
5039  return ret;
5040 }
5041 
5042 static bool
5044 {
5046 }
5047 
5048 void
5050 {
5051  context.claim_system_worker ();
5052  context.conn_entry = m_conn;
5053 }
5054 
5055 void
5057 {
5058  context.retire_system_worker ();
5059  context.conn_entry = NULL;
5060 }
5061 
5062 void
5064 {
5066 }
5067 
5069  index_builder_loader_context &load_context,
5070  std::atomic<int> &num_keys, std::atomic<int> &num_oids,
5071  std::atomic<int> &num_nulls)
5072  : m_load_context (load_context)
5073  , m_insert_list (load_context.m_key_type)
5074  , m_num_keys (num_keys)
5075  , m_num_oids (num_oids)
5076  , m_num_nulls (num_nulls)
5077 {
5078  BTID_COPY (&m_btid, btid);
5079  COPY_OID (&m_class_oid, class_oid);
5080  m_unique_pk = unique_pk;
5081  m_load_context.m_has_error = false;
5082  m_memsize = 0;
5083 }
5084 
5086 {
5088 }
5089 
5092 {
5093  if (DB_IS_NULL (key) || btree_multicol_key_is_null (const_cast<DB_VALUE *>(key)))
5094  {
5095  /* We do not store NULL keys, but we track them for unique indexes;
5096  * for non-unique, just skip row */
5098  {
5100  }
5101  return BATCH_CONTINUE;
5102  }
5103 
5104  size_t entry_size = m_insert_list.add_key (key, oid);
5105 
5106  m_memsize += entry_size;
5107 
5109 }
5110 
5111 bool
5113 {
5114  return !m_insert_list.m_keys_oids.empty ();
5115 }
5116 
5117 void
5119 {
5120  for (auto &key_oid : m_insert_list.m_keys_oids)
5121  {
5123  }
5124 }
5125 
5126 void
5128 {
5129  int ret = NO_ERROR;
5130  size_t key_count = 0;
5131  LOG_TRAN_BTID_UNIQUE_STATS *p_unique_stats;
5132 
5133  /* Check for possible errors set by the other threads. */
5135  {
5136  return;
5137  }
5138 
5139  PERF_UTIME_TRACKER time_insert_task = PERF_UTIME_TRACKER_INITIALIZER;
5140  PERF_UTIME_TRACKER_START (&thread_ref, &time_insert_task);
5141 
5142  PERF_UTIME_TRACKER time_prepare_task = PERF_UTIME_TRACKER_INITIALIZER;
5143  PERF_UTIME_TRACKER_START (&thread_ref, &time_prepare_task);
5144 
5146 
5147  PERF_UTIME_TRACKER_TIME (&thread_ref, &time_prepare_task, PSTAT_BT_ONLINE_PREPARE_TASK);
5148 
5150  {
5153 
5154  if (ret != NO_ERROR)
5155  {
5156  if (!m_load_context.m_has_error.exchange (true))
5157  {
5159  // TODO: We need a mechanism to also copy the error message!!
5160  }
5161  break;
5162  }
5163 
5164  key_count++;
5165  }
5166 
5167  p_unique_stats = logtb_tran_find_btid_stats (&thread_ref, &m_btid, false);
5168  if (p_unique_stats != NULL)
5169  {
5170  /* Cumulates and resets statistics */
5171  m_num_keys += p_unique_stats->tran_stats.num_keys;
5174 
5175  p_unique_stats->tran_stats.num_keys = 0;
5176  p_unique_stats->tran_stats.num_oids = 0;
5177  p_unique_stats->tran_stats.num_nulls = 0;
5178  }
5179 
5180  PERF_UTIME_TRACKER_TIME (&thread_ref, &time_insert_task, PSTAT_BT_ONLINE_INSERT_TASK);
5181 
5182  /* Increment tasks executed. */
5184  {
5185  _er_log_debug (ARG_FILE_LINE, "Finished task; loaded %zu keys\n", key_count);
5186  }
5187 
5189 }
5190 // *INDENT-ON*
#define HEADER
Definition: btree_load.h:100
int btree_change_root_header_delta(THREAD_ENTRY *thread_p, VFID *vfid, PAGE_PTR page_ptr, int null_delta, int oid_delta, int key_delta)
Definition: btree_load.c:461
int attrinfo_inited
Definition: btree_load.c:77
char * PAGE_PTR
TP_DOMAIN * btree_generate_prefix_domain(BTID_INT *btid)
Definition: btree.c:5749
std::atomic< int > & m_num_nulls
Definition: btree_load.c:192
int data_readval(struct or_buf *buf, DB_VALUE *value, const tp_domain *domain, int size, bool copy, char *copy_buf, int copy_buf_len) const
#define MAX_PARTITIONS
Definition: partition.h:26
#define OR_BTID_ALIGNED_SIZE
#define OR_PUT_OID(ptr, oid)
TP_DOMAIN * key_type
Definition: btree_load.c:69
OID * oid_Root_class_oid
Definition: oid.c:73
#define NO_ERROR
Definition: error_code.h:46
FUNCTION_INDEX_INFO * func_index_info
Definition: btree_load.c:86
int area_size
void log_append_redo_data(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int length, const void *data)
Definition: log_manager.c:1979
static int list_add(BTREE_NODE **list, VPID *pageid)
Definition: btree_load.c:3597
OID * fk_refcls_oid
Definition: btree_load.c:81
#define MVCC_IS_HEADER_DELID_VALID(rec_header_p)
Definition: mvcc.h:87
#define MVCC_GET_INSID(header)
Definition: mvcc.h:51
MVCC_SNAPSHOT * logtb_get_mvcc_snapshot(THREAD_ENTRY *thread_p)
int or_get_mvccid(OR_BUF *buf, MVCCID *mvccid)
int btree_create_file(THREAD_ENTRY *thread_p, const OID *class_oid, int attrid, BTID *btid)
Definition: btree.c:32892
#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
char * copy_buf
Definition: btree.h:130
size_t add_key(const DB_VALUE *key, const OID &oid)
Definition: btree.c:35621
static void btree_log_page(THREAD_ENTRY *thread_p, VFID *vfid, PAGE_PTR page_ptr)
Definition: btree_load.c:1961
BTREE_NODE_HEADER * btree_get_node_header(THREAD_ENTRY *thread_p, PAGE_PTR page_ptr)
Definition: btree_load.c:275
PRUNING_CONTEXT pcontext
Definition: btree_load.c:157
static int btree_first_oid(THREAD_ENTRY *thread_p, DB_VALUE *this_key, OID *class_oid, OID *first_oid, MVCC_REC_HEADER *p_mvcc_rec_header, LOAD_ARGS *load_args)
Definition: btree_load.c:2153
BTID * sys_btid
Definition: btree.h:121
#define ASSERT_ERROR()
SCAN_CODE
void claim_system_worker()
#define OR_MULTI_ATT_IS_UNBOUND(bitptr, element)
#define BTREE_NORMAL_KEY
Definition: btree.h:93
int or_put_oid(OR_BUF *buf, const OID *oid)
static int online_index_builder(THREAD_ENTRY *thread_p, BTID_INT *btid_int, HFID *hfids, OID *class_oids, int n_classes, int *attrids, int n_attrs, FUNCTION_INDEX_INFO func_idx_info, PRED_EXPR_WITH_CONTEXT *filter_pred, int *attrs_prefix_length, HEAP_CACHE_ATTRINFO *attr_info, HEAP_SCANCACHE *scancache, int unique_pk, int ib_thread_count, TP_DOMAIN *key_type)
Definition: btree_load.c:4831
#define BTREE_GET_KEY_LEN_IN_PAGE(key_len)
Definition: btree_load.h:155
static PAGE_PTR btree_proceed_leaf(THREAD_ENTRY *thread_p, LOAD_ARGS *load_args)
Definition: btree_load.c:2076
int data_writeval(struct or_buf *buf, const DB_VALUE *value) const
BTREE_NODE_HEADER hdr
Definition: btree_load.c:96
#define ER_NOT_NULL_DOES_NOT_ALLOW_NULL_VALUE
Definition: error_code.h:1424
void btree_mvcc_info_from_heap_mvcc_header(MVCC_REC_HEADER *mvcc_header, BTREE_MVCC_INFO *mvcc_info)
Definition: btree.c:28752
DB_VALUE current_key
Definition: btree_load.c:109
bool cache_last_fix_page
Definition: heap_file.h:148
int btree_write_record(THREAD_ENTRY *thread_p, BTID_INT *btid, void *node_rec, DB_VALUE *key, BTREE_NODE_TYPE node_type, int key_type, int key_len, bool during_loading, OID *class_oid, OID *oid, BTREE_MVCC_INFO *mvcc_info, RECDES *rec)
Definition: btree.c:4076
VPID C_vpid
Definition: btree.h:173
int or_put_domain(OR_BUF *buf, struct tp_domain *domain, int include_classoids, int is_null)
int spage_insert(THREAD_ENTRY *thread_p, PAGE_PTR page_p, RECDES *record_descriptor_p, PGSLOTID *out_slot_id_p)
int n_attrs
Definition: btree_load.c:66
int partition_load_pruning_context(THREAD_ENTRY *thread_p, const OID *class_oid, int pruning_type, PRUNING_CONTEXT *pinfo)
Definition: partition.c:2249
DB_TYPE
Definition: dbtype_def.h:670
#define ER_FAILED
Definition: error_code.h:47
BTREE_ROOT_HEADER * btree_get_root_header(THREAD_ENTRY *thread_p, PAGE_PTR page_ptr)
Definition: btree_load.c:309
const int LOG_SYSTEM_TRAN_INDEX
const char * bt_name
Definition: btree_load.c:103
VFID ovfid
Definition: btree.h:129
LOG_GLOBAL log_Gl
css_conn_entry * conn_entry
int SORT_PUT_FUNC(THREAD_ENTRY *thread_p, const RECDES *, void *)
Definition: external_sort.h:60
struct tp_domain * setdomain
Definition: object_domain.h:82
#define DISK_VPID_SIZE
ATTR_ID * attrids_pred
Definition: xasl.h:1060
bool has_deadlock_priority
Definition: log_impl.h:536
#define OR_BUF_INIT(buf, data, size)
#define BTREE_SET_CREATED_OVERFLOW_KEY_NOTIFICATION(THREAD, KEY, OID, C_OID, BTID, BTNM)
Definition: btree_load.h:159
#define MVCC_IS_HEADER_INSID_NOT_ALL_VISIBLE(rec_header_p)
Definition: mvcc.h:91
MVCCID oldest_visible_mvccid
Definition: btree_load.c:88
void logpb_force_flush_pages(THREAD_ENTRY *thread_p)
void on_create(context_type &context) override
Definition: btree_load.c:5049
int n_classes
Definition: btree_load.c:74
struct btree_node_header BTREE_NODE_HEADER
Definition: btree_load.h:193
#define NO_SORT_LIMIT
Definition: external_sort.h:40
#define ASSERT_ERROR_AND_SET(error_code)
int or_get_oid(OR_BUF *buf, OID *oid)
bool logtb_set_tran_index_interrupt(THREAD_ENTRY *thread_p, int tran_index, bool set)
void thread_sleep(double millisec)
std::atomic< int > & m_num_oids
Definition: btree_load.c:191
#define OR_MVCC_FLAG_VALID_INSID
TP_DOMAIN * nonleaf_key_type
Definition: btree.h:125
BTID * xbtree_add_index(THREAD_ENTRY *thread_p, BTID *btid, TP_DOMAIN *key_type, OID *class_oid, int attr_id, int unique_pk, int num_oids, int num_nulls, int num_keys)
Definition: btree.c:5579
#define assert_release(e)
Definition: error_manager.h:96
void on_retire(context_type &context) override
Definition: btree_load.c:5056
int lock_demote_class_lock(THREAD_ENTRY *thread_p, const OID *oid, LOCK lock, LOCK *ex_lock)
void pgbuf_set_dirty(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, bool free_page)
Definition: page_buffer.c:4280
void scan_init_index_scan(INDX_SCAN_ID *isidp, struct btree_iscan_oid_list *oid_list, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: scan_manager.c:283
#define BTREE_MAX_OIDLEN_INPAGE
Definition: btree_load.h:137
BTREE_NODE_HEADER * header
Definition: btree_load.c:151
static void list_clear(BTREE_NODE *list)
Definition: btree_load.c:3660
OID cur_oid
Definition: btree_load.c:64
void log_append_undo_data2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, int length, const void *data)
Definition: log_manager.c:1933
int or_mvcc_get_header(RECDES *record, MVCC_REC_HEADER *mvcc_header)
static int btree_save_last_leafrec(THREAD_ENTRY *thread_p, LOAD_ARGS *load_args)
Definition: btree_load.c:1223
int lock_object(THREAD_ENTRY *thread_p, const OID *oid, const OID *class_oid, LOCK lock, int cond_flag)
#define MVCCID_NULL
void log_sysop_start(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3578
cubthread::manager * thread_get_manager(void)
#define OR_MVCC_FLAG_VALID_DELID
#define OR_MVCCID_SIZE
#define OR_ALIGNED_BUF(size)
static int btree_build_nleafs(THREAD_ENTRY *thread_p, LOAD_ARGS *load_args, int n_nulls, int n_oids, int n_keys)
Definition: btree_load.c:1449
BTREE_PAGE nleaf
Definition: btree_load.c:118
#define OID_SET_NULL(oidp)
Definition: oid.h:85
#define os_free_and_init(ptr)
Definition: memory_alloc.h:153
#define OID_LT(oidp1, oidp2)
Definition: oid.h:113
static int btree_load_new_page(THREAD_ENTRY *thread_p, const BTID *btid, BTREE_NODE_HEADER *header, int node_level, VPID *vpid_new, PAGE_PTR *page_new)
Definition: btree_load.c:1987
DB_LOGICAL(* PR_EVAL_FNC)(THREAD_ENTRY *thread_p, const PRED_EXPR *, val_descr *, OID *)
bool btree_multicol_key_is_null(DB_VALUE *key)
Definition: btree.c:18033
#define PEEK_KEY_VALUE
Definition: btree_load.h:44
int btree_node_number_of_keys(THREAD_ENTRY *thread_p, PAGE_PTR page_ptr)
Definition: btree_load.c:3755
char * data
#define CAST_STRLEN
Definition: porting.h:470
std::atomic< int > & m_num_keys
Definition: btree_load.c:190
INT16 slot_id
Definition: btree.h:186
#define OR_GET_BYTE(ptr)
int32_t pageid
Definition: dbtype_def.h:879
INT32 root_pageid
const int LOG_WORKER_POOL_INDEX_BUILDER
#define MVCC_CLEAR_FLAG_BITS(rec_header_p, flag)
Definition: mvcc.h:101
void btree_init_temp_key_value(bool *clear_flag, DB_VALUE *key_value)
Definition: btree.c:1938
int not_null_flag
Definition: btree_load.c:61
bool overflowing
Definition: btree_load.c:128
int er_errid(void)
entry_workpool * create_worker_pool(std::size_t pool_size, std::size_t task_max_count, const char *name, entry_manager *context_manager, std::size_t core_count, bool debug_logging, bool pool_threads=false, wait_seconds wait_for_task_time=std::chrono::seconds(5))
int max_key_size
Definition: btree_load.c:110
#define SP_SUCCESS
Definition: slotted_page.h:50
int n_oids
Definition: btree_load.c:73
static PAGE_PTR btree_connect_page(THREAD_ENTRY *thread_p, DB_VALUE *key, int max_key_len, VPID *pageid, LOAD_ARGS *load_args, int node_level)
Definition: btree_load.c:1335
MVCC_SATISFIES_SNAPSHOT_RESULT mvcc_satisfies_dirty(THREAD_ENTRY *thread_p, MVCC_REC_HEADER *rec_header, MVCC_SNAPSHOT *snapshot)
Definition: mvcc.c:501
static bool btree_is_worker_pool_logging_true()
Definition: btree_load.c:5043
#define OR_MULTI_BOUND_BIT_BYTES(count)
#define BTREE_IS_UNIQUE(unique_pk)
Definition: btree.h:89
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
PRED_EXPR_WITH_CONTEXT * filter
Definition: btree_load.c:84
void prepare_list(void)
Definition: btree.c:35706
struct btree_overflow_header BTREE_OVERFLOW_HEADER
Definition: btree_load.h:223
#define OID_AS_ARGS(oidp)
Definition: oid.h:39
int btree_check_valid_record(THREAD_ENTRY *thread_p, BTID_INT *btid, RECDES *recp, BTREE_NODE_TYPE node_type, DB_VALUE *key)
Definition: btree.c:21828
#define er_log_debug(...)
static int btree_index_sort(THREAD_ENTRY *thread_p, SORT_ARGS *sort_args, SORT_PUT_FUNC *out_func, void *out_args)
Definition: btree_load.c:2928
DB_VALUE_COMPARE_RESULT btree_compare_key(DB_VALUE *key1, DB_VALUE *key2, TP_DOMAIN *key_domain, int do_coercion, int total_order, int *start_colp)
Definition: btree.c:18636
void execute(cubthread::entry &thread_ref)
Definition: btree_load.c:5127
int heap_scancache_end(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache)
Definition: heap_file.c:7195
void _er_log_debug(const char *file_name, const int line_no, const char *fmt,...)
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
#define COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:63
#define BTREE_MAX_KEYLEN_INPAGE
Definition: btree_load.h:135
SCAN_CODE spage_get_record(THREAD_ENTRY *thread_p, PAGE_PTR page_p, PGSLOTID slot_id, RECDES *record_descriptor_p, int is_peeking)
#define DBVAL_BUFSIZE
Definition: btree.h:449
int xlogtb_reset_wait_msecs(THREAD_ENTRY *thread_p, int wait_msecs)
void btree_rv_mvcc_save_increments(const BTID *btid, int key_delta, int oid_delta, int null_delta, RECDES *recdes)
Definition: btree_load.c:645
#define VFID_ISNULL(vfid_ptr)
Definition: file_manager.h:72
int copy_buf_len
Definition: btree.h:131
void THREAD_ENTRY
mvcctable mvcc_table
Definition: log_impl.h:684
#define NULL_PAGEID
#define MVCCID_ALL_VISIBLE
#define pgbuf_unfix_and_init(thread_p, pgptr)
Definition: page_buffer.h:63
#define MVCC_SET_INSID(header, mvcc_id)
Definition: mvcc.h:54
void vacuum_log_add_dropped_file(THREAD_ENTRY *thread_p, const VFID *vfid, const OID *class_oid, bool pospone_or_undo)
Definition: vacuum.c:6024
int ATTR_ID
int btree_create_overflow_key_file(THREAD_ENTRY *thread_p, BTID_INT *btid)
Definition: btree.c:1953
int or_put_mvccid(OR_BUF *buf, MVCCID mvccid)
#define OR_ALIGNED_BUF_START(abuf)
int spage_update(THREAD_ENTRY *thread_p, PAGE_PTR page_p, PGSLOTID slot_id, const RECDES *record_descriptor_p)
LOCK
#define FREE(PTR)
Definition: cas_common.h:56
void log_append_redo_data2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, int length, const void *data)
Definition: log_manager.c:1995
int heap_scancache_start(THREAD_ENTRY *thread_p, HEAP_SCANCACHE *scan_cache, const HFID *hfid, const OID *class_oid, int cache_last_fix_page, int is_indexscan, MVCC_SNAPSHOT *mvcc_snapshot)
Definition: heap_file.c:6833
void switch_to_global_allocator_and_call(Func &&func, Args &&...args)
UINT64 prm_get_bigint_value(PARAM_ID prm_id)
int sort_listfile(THREAD_ENTRY *thread_p, INT16 volid, int est_inp_pg_cnt, SORT_GET_FUNC *get_fn, void *get_arg, SORT_PUT_FUNC *put_fn, void *put_arg, SORT_CMP_FUNC *cmp_fn, void *cmp_arg, SORT_DUP_OPTION option, int limit, bool includes_tde_class)
void partition_clear_pruning_context(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2380
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 heap_attrinfo_start(THREAD_ENTRY *thread_p, const OID *class_oid, int requested_num_attrs, const ATTR_ID *attrids, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:9427
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
void btree_clear_mvcc_flags_from_oid(OID *oid)
Definition: btree.c:21763
int spage_max_space_for_new_record(THREAD_ENTRY *thread_p, PAGE_PTR page_p)
Definition: slotted_page.c:984
int part_key_desc
Definition: btree.h:123
char * btree_pack_mvccinfo(char *ptr, BTREE_MVCC_INFO *mvcc_info)
Definition: btree.c:21369
#define BTREE_INIT_MVCC_HEADER(p_mvcc_rec_header)
Definition: btree.h:451
BTID * xbtree_load_online_index(THREAD_ENTRY *thread_p, BTID *btid, const char *bt_name, TP_DOMAIN *key_type, OID *class_oids, int n_classes, int n_attrs, int *attr_ids, int *attrs_prefix_length, HFID *hfids, int unique_pk, int not_null_flag, OID *fk_refcls_oid, BTID *fk_refcls_pk_btid, const char *fk_name, char *pred_stream, int pred_stream_size, char *func_pred_stream, int func_pred_stream_size, int func_col_id, int func_attr_index_start, int ib_thread_count)
Definition: btree_load.c:4438
#define BTREE_MAX_OIDCOUNT_IN_SIZE(btid, size)
Definition: btree_load.h:140
const char * fk_name
Definition: btree_load.c:83
#define assert(x)
#define BTREE_MAX_OIDCOUNT_IN_LEAF_RECORD(btid)
Definition: btree_load.h:143
void btree_leaf_record_change_overflow_link(THREAD_ENTRY *thread_p, BTID_INT *btid_int, RECDES *leaf_record, VPID *new_overflow_vpid, char **rv_undo_data_ptr, char **rv_redo_data_ptr)
Definition: btree.c:2296
#define DB_NEED_CLEAR(v)
Definition: dbtype.h:83
BTREE_NODE_HEADER node
Definition: btree_load.h:207
int btree_online_index_list_dispatcher(THREAD_ENTRY *thread_p, BTID *btid, OID *class_oid, btree_insert_list *insert_list, int unique, BTREE_OP_PURPOSE purpose, LOG_LSA *undo_nxlsa)
Definition: btree.c:33293
TDE_ALGORITHM
Definition: tde.h:71
int32_t fileid
Definition: dbtype_def.h:886
void btree_mvcc_info_to_heap_mvcc_header(BTREE_MVCC_INFO *mvcc_info, MVCC_REC_HEADER *mvcc_header)
Definition: btree.c:28787
bool pgbuf_check_page_ptype(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, PAGE_TYPE ptype)
static int compare_driver(const void *first, const void *second, void *arg)
Definition: btree_load.c:3382
#define ER_GENERIC_ERROR
Definition: error_code.h:49
int btree_rv_save_keyval_for_undo(BTID_INT *btid, DB_VALUE *key, OID *cls_oid, OID *oid, BTREE_MVCC_INFO *mvcc_info, BTREE_OP_PURPOSE purpose, char *preallocated_buffer, char **data, int *capacity, int *length)
Definition: btree.c:16504
#define ER_FK_INVALID
Definition: error_code.h:1153
int partition_prune_unique_btid(PRUNING_CONTEXT *pcontext, DB_VALUE *key, OID *class_oid, HFID *class_hfid, BTID *btid)
Definition: partition.c:3553
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
int rev_level
Definition: btree.h:132
BTID_INT btid_int
Definition: btree.h:165
int btree_init_root_header(THREAD_ENTRY *thread_p, VFID *vfid, PAGE_PTR page_ptr, BTREE_ROOT_HEADER *root_header, TP_DOMAIN *key_type)
Definition: btree_load.c:540
int btree_get_next_overflow_vpid(THREAD_ENTRY *thread_p, PAGE_PTR page_ptr, VPID *vpid)
Definition: btree_load.c:677
#define SORT_RECORD_LENGTH(item_p)
Definition: external_sort.h:43
unsigned is_desc
#define BTID_INITIALIZER
#define OR_GET_OID(ptr, oid)
RECDES * out_recdes
Definition: btree_load.c:105
void btree_get_root_vpid_from_btid(THREAD_ENTRY *thread_p, BTID *btid, VPID *root_vpid)
Definition: btree.c:6912
bool css_is_shutdowning_server()
ATTR_ID * attr_ids
Definition: btree_load.c:67
static int list_length(const BTREE_NODE *this_list)
Definition: btree_load.c:3681
BTREE_NODE_TYPE
Definition: btree.h:81
int cur_class
Definition: btree_load.c:75
batch_key_status add_key(const DB_VALUE *key, const OID &oid)
Definition: btree_load.c:5091
int or_put_byte(OR_BUF *buf, int num)
MVCCID creator_mvccid
Definition: btree_load.h:216
short volid
Definition: dbtype_def.h:880
void btree_rv_nodehdr_dump(FILE *fp, int length, void *data)
Definition: btree_load.c:3737
int stx_map_stream_to_func_pred(THREAD_ENTRY *thread_p, func_pred **xasl, char *xasl_stream, int xasl_stream_size, XASL_UNPACK_INFO **xasl_unpack_info_ptr)
#define OID_EQ(oidp1, oidp2)
Definition: oid.h:92
static int btree_get_value_from_leaf_slot(THREAD_ENTRY *thread_p, BTID_INT *btid_int, PAGE_PTR leaf_ptr, int slot_id, DB_VALUE *key, bool *clear_key)
Definition: btree_load.c:4207
#define heap_classrepr_free_and_init(class_repr, idxp)
Definition: heap_file.h:91
const TP_DOMAIN * m_key_type
Definition: btree_load.c:169
std::atomic< std::uint64_t > m_tasks_executed
Definition: btree_load.c:167
int heap_attrinfo_read_dbvalues(THREAD_ENTRY *thread_p, const OID *inst_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:10337
VFID vfid
#define TP_DOMAIN_TYPE(dom)
PAGE_PTR pgptr
Definition: btree_load.c:95
int btree_init_overflow_header(THREAD_ENTRY *thread_p, PAGE_PTR page_ptr, BTREE_OVERFLOW_HEADER *ovf_header)
Definition: btree_load.c:579
char * new_pos
Definition: btree_load.c:108
#define NULL
Definition: freelistheap.h:34
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 btree_dump_key(FILE *fp, const DB_VALUE *key)
Definition: btree.c:4615
UINT64 MVCCID
void btree_set_mvcc_flags_into_oid(MVCC_REC_HEADER *p_mvcc_header, OID *oid)
Definition: btree.c:21739
PGNSLOTS spage_number_of_records(PAGE_PTR page_p)
Definition: slotted_page.c:860
#define MVCC_IS_FLAG_SET(rec_header_p, flags)
Definition: mvcc.h:84
struct pr_type * type
Definition: object_domain.h:76
int logtb_invalidate_snapshot_data(THREAD_ENTRY *thread_p)
#define BTREE_CURRENT_REV_LEVEL
Definition: btree_load.h:50
Definition: btree.h:536
DISK_ISVALID btree_verify_tree(THREAD_ENTRY *thread_p, const OID *class_oid_p, BTID_INT *btid_int, const char *btname)
Definition: btree.c:7568
if(extra_options)
Definition: dynamic_load.c:958
PAGE_PTR C_page
Definition: btree.h:181
const VFID * vfid
Definition: log_append.hpp:56
VFID vfid
DB_VALUE * heap_attrinfo_generate_key(THREAD_ENTRY *thread_p, int n_atts, int *att_ids, int *atts_prefix_length, HEAP_CACHE_ATTRINFO *attr_info, RECDES *recdes, DB_VALUE *db_valuep, char *buf, FUNCTION_INDEX_INFO *func_index_info, TP_DOMAIN *midxkey_domain)
Definition: heap_file.c:12672
static int btree_construct_leafs(THREAD_ENTRY *thread_p, const RECDES *in_recdes, void *arg)
Definition: btree_load.c:2216
int curr_rec_max_obj_count
Definition: btree_load.c:135
#define BTID_SET_NULL(btid)
VPID pnt
Definition: btree.h:105
#define BTREE_OVERFLOW_KEY
Definition: btree.h:94
int curr_non_del_obj_count
Definition: btree_load.c:133
PAGE_PTR pgptr
Definition: log_append.hpp:57
#define LOAD_FIXED_EMPTY_FOR_NONLEAF
Definition: btree_load.h:58
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
#define OR_PUT_BTID(ptr, btid)
int curr_rec_obj_count
Definition: btree_load.c:136
#define ER_BTREE_LOAD_FAILED
Definition: error_code.h:846
#define pgbuf_fix(thread_p, vpid, fetch_mode, requestmode, condition)
Definition: page_buffer.h:255
BTREE_NODE * next
Definition: btree_load.h:249
BTREE_PAGE ovf
Definition: btree_load.c:126
void partition_init_pruning_context(PRUNING_CONTEXT *pinfo)
Definition: partition.c:2164
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
int btree_prepare_bts(THREAD_ENTRY *thread_p, BTREE_SCAN *bts, BTID *btid, INDX_SCAN_ID *index_scan_id_p, key_val_range *kv_range, FILTER_INFO *filter, const OID *match_class_oid, DB_BIGINT *key_limit_upper, DB_BIGINT *key_limit_lower, bool need_to_check_null, void *bts_other)
Definition: btree.c:15049
void or_init(OR_BUF *buf, char *data, int length)
int n_keys
Definition: btree_load.c:130
int scancache_inited
Definition: btree_load.c:76
LOG_UNIQUE_STATS tran_stats
Definition: log_impl.h:376
static void list_remove_first(BTREE_NODE **list)
Definition: btree_load.c:3642
#define MVCC_REC_HEADER_INITIALIZER
Definition: mvcc.h:47
const OID oid_Null_oid
Definition: oid.c:68
PR_EVAL_FNC filter_eval_func
Definition: btree_load.c:85
BTREE_NODE * push_list
Definition: btree_load.c:114
#define NULL_OFFSET
need_clear_type need_clear
Definition: dbtype_def.h:1084
SORT_STATUS
Definition: external_sort.h:45
int partition_prune_partition_index(PRUNING_CONTEXT *pcontext, DB_VALUE *key, OID *class_oid, BTID *btid, int *position)
Definition: partition.c:3926
bool logtb_set_check_interrupt(THREAD_ENTRY *thread_p, bool flag)
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
int pr_clear_value(DB_VALUE *value)
int m_ignored_nulls_cnt
Definition: btree.h:586
index_builder_loader_context & m_load_context
Definition: btree_load.c:186
static int btree_pack_root_header(RECDES *Rec, BTREE_ROOT_HEADER *header, TP_DOMAIN *key_type)
Definition: btree_load.c:502
offset_type offset
Definition: log_append.hpp:58
DB_VALUE m_key
Definition: btree.h:538
void log_sysop_abort(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4017
#define NULL_REPRID
#define MVCC_SET_FLAG_BITS(rec_header_p, flag)
Definition: mvcc.h:95
void destroy_worker_pool(entry_workpool *&worker_pool_arg)
int btree_get_num_visible_from_leaf_and_ovf(THREAD_ENTRY *thread_p, BTID_INT *btid_int, RECDES *leaf_record, int offset_after_key, LEAF_REC *leaf_info, int *max_visible_oids, MVCC_SNAPSHOT *mvcc_snapshot, int *num_visible)
Definition: btree.c:2566
MVCCID logtb_get_current_mvccid(THREAD_ENTRY *thread_p)
#define CAST_BUFLEN
Definition: porting.h:471
void free_xasl_unpack_info(THREAD_ENTRY *thread_p, REFPTR(XASL_UNPACK_INFO, xasl_unpack_info))
bool logtb_is_interrupted(THREAD_ENTRY *thread_p, bool clear, bool *continue_checking)
#define ER_BTREE_UNIQUE_FAILED
Definition: error_code.h:811
static void error(const char *msg)
Definition: gencat.c:331
int btree_get_disk_size_of_key(DB_VALUE *key)
Definition: btree.c:4041
btree_insert_list m_insert_list
Definition: btree_load.c:187
#define VPID_ISNULL(vpid_ptr)
Definition: dbtype_def.h:925
int btree_get_prefix_separator(const DB_VALUE *key1, const DB_VALUE *key2, DB_VALUE *prefix_key, TP_DOMAIN *key_domain)
Definition: btree.c:11763
static int rc
Definition: serial.c:50
#define ER_INTERRUPTED
Definition: error_code.h:51
int heap_get_btid_from_index_name(THREAD_ENTRY *thread_p, const OID *p_class_oid, const char *index_name, BTID *p_found_btid)
Definition: heap_file.c:16938
MVCCID get_global_oldest_visible() const
Definition: mvcc_table.cpp:612
LOG_TDES * LOG_FIND_CURRENT_TDES(THREAD_ENTRY *thread_p=NULL)
Definition: log_impl.h:1115
PGSLOTID last_leaf_insert_slotid
Definition: btree_load.c:138
bool log_check_system_op_is_started(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4166
#define HFID_IS_NULL(hfid)
#define ARG_FILE_LINE
Definition: error_manager.h:44
int btree_online_index_check_unique_constraint(THREAD_ENTRY *thread_p, BTID *btid, const char *index_name, OID *class_oid)
Definition: btree.c:35273
#define OR_BYTE_SIZE
int pr_clone_value(const DB_VALUE *src, DB_VALUE *dest)
#define BTREE_IS_PRIMARY_KEY(unique_pk)
Definition: btree.h:88
RECDES in_recdes
Definition: btree_load.c:65
static const bool COPY
BTID * fk_refcls_pk_btid
Definition: btree_load.c:82
PR_EVAL_FNC eval_fnc(THREAD_ENTRY *thread_p, const PRED_EXPR *pr, DB_TYPE *single_node_type)
void on_recycle(context_type &context) override
Definition: btree_load.c:5063
int btree_node_header_undo_log(THREAD_ENTRY *thread_p, VFID *vfid, PAGE_PTR page_ptr)
Definition: btree_load.c:414
MVCC_SNAPSHOT * mvcc_snapshot
Definition: heap_file.h:154
int pr_is_prefix_key_type(DB_TYPE type)
RECDES leaf_nleaf_recdes
Definition: btree_load.c:106
INT16 PGSLOTID
int btree_initialize_new_page(THREAD_ENTRY *thread_p, PAGE_PTR page, void *args)
Definition: btree.c:4971
#define BTREE_MAX_ALIGN
Definition: btree_load.h:66
#define ER_TF_CORRUPTED
Definition: error_code.h:394
BTREE_OVERFLOW_HEADER * btree_get_overflow_header(THREAD_ENTRY *thread_p, PAGE_PTR page_ptr)
Definition: btree_load.c:344
void btree_leaf_change_first_object(THREAD_ENTRY *thread_p, RECDES *recp, BTID_INT *btid, OID *oidp, OID *class_oidp, BTREE_MVCC_INFO *mvcc_info, int *key_offset, char **rv_undo_data_ptr, char **rv_redo_data_ptr)
Definition: btree.c:2798
#define BTID_COPY(btid_ptr1, btid_ptr2)
void BTREE_MVCC_SET_HEADER_FIXED_SIZE(MVCC_REC_HEADER *p_mvcc_rec_header)
Definition: btree_load.h:173
OID topclass_oid
Definition: btree.h:133
BTID * xbtree_load_index(THREAD_ENTRY *thread_p, BTID *btid, const char *bt_name, TP_DOMAIN *key_type, OID *class_oids, int n_classes, int n_attrs, int *attr_ids, int *attrs_prefix_length, HFID *hfids, int unique_pk, int not_null_flag, OID *fk_refcls_oid, BTID *fk_refcls_pk_btid, const char *fk_name, char *pred_stream, int pred_stream_size, char *func_pred_stream, int func_pred_stream_size, int func_col_id, int func_attr_index_start)
Definition: btree_load.c:716
VPID pageid
Definition: btree_load.h:250
#define DB_PAGESIZE
int unique_pk
Definition: btree_load.c:60
#define MVCC_GET_DELID(header)
Definition: mvcc.h:57
#define os_malloc(size)
Definition: memory_alloc.h:167
bool prm_get_bool_value(PARAM_ID prm_id)
#define INT_ALIGNMENT
Definition: memory_alloc.h:61
#define OR_PUT_INT(ptr, val)
static int btree_advance_to_next_slot_and_fix_page(THREAD_ENTRY *thread_p, BTID_INT *btid, VPID *vpid, PAGE_PTR *pg_ptr, INT16 *slot_id, DB_VALUE *key, bool *clear_key, bool is_desc, int *key_cnt, BTREE_NODE_HEADER **header, MVCC_SNAPSHOT *mvcc)
Definition: btree_load.c:4253
HEAP_CACHE_ATTRINFO * cache_attrinfo
Definition: xasl.h:278
int btree_locate_key(THREAD_ENTRY *thread_p, BTID_INT *btid_int, DB_VALUE *key, VPID *pg_vpid, INT16 *slot_id, PAGE_PTR *leaf_page_out, bool *found_p)
Definition: btree.c:14151
void er_clear(void)
void log_sysop_attach_to_outer(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4076
std::vector< key_oid * > m_sorted_keys_oids
Definition: btree.h:578
void log_sysop_commit(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3895
static SORT_STATUS btree_sort_get_next(THREAD_ENTRY *thread_p, RECDES *temp_recdes, void *arg)
Definition: btree_load.c:2966
int btree_leaf_get_first_object(BTID_INT *btid, RECDES *recp, OID *oidp, OID *class_oid, BTREE_MVCC_INFO *mvcc_info)
Definition: btree.c:2429
PRED_EXPR * pred
Definition: xasl.h:1058
int btree_multicol_key_has_null(DB_VALUE *key)
Definition: btree.c:18079
int i
Definition: dynamic_load.c:954
BTREE_PAGE leaf
Definition: btree_load.c:124
int db_make_null(DB_VALUE *value)
char * pr_valstring(const DB_VALUE *val)
#define ER_IB_ERROR_ABORT
Definition: error_code.h:1599
OID * class_ids
Definition: btree_load.c:63
#define DB_IS_NULL(value)
Definition: dbtype.h:63
#define LOAD_FIXED_EMPTY_FOR_LEAF
Definition: btree_load.h:55
struct tp_domain * next
Definition: object_domain.h:74
int qexec_clear_pred_context(THREAD_ENTRY *thread_p, pred_expr_with_context *pred_filter, bool dealloc_dbvalues)
struct func_pred * expr
Definition: heap_file.h:223
VPID vpid
Definition: btree_load.c:94
INT16 type
std::vector< key_oid > m_keys_oids
Definition: btree.h:577
bool btree_clear_key_value(bool *clear_flag, DB_VALUE *key_value)
Definition: btree.c:1919
MVCC_SNAPSHOT_FUNC snapshot_fnc
Definition: mvcc.h:176
int btree_init_node_header(THREAD_ENTRY *thread_p, const VFID *vfid, PAGE_PTR page_ptr, BTREE_NODE_HEADER *header, bool redo)
Definition: btree_load.c:373
#define IO_MAX_PAGE_SIZE
#define BTID_IS_NULL(btid)
int * attrs_prefix_length
Definition: btree_load.c:68
int setval(DB_VALUE *dest, const DB_VALUE *src, bool copy) const
HEAP_SCANCACHE hfscan_cache
Definition: btree_load.c:70
void heap_attrinfo_end(THREAD_ENTRY *thread_p, HEAP_CACHE_ATTRINFO *attr_info)
Definition: heap_file.c:9979
BTREE_NODE * pop_list
Definition: btree_load.c:115
short volid
Definition: dbtype_def.h:887
int unique_pk
Definition: btree.h:122
#define OID_ISNULL(oidp)
Definition: oid.h:81
BTID_INT * btid
Definition: btree_load.c:79
enum mvcc_satisfies_snapshot_result MVCC_SATISFIES_SNAPSHOT_RESULT
Definition: mvcc.h:164
#define DONT_FREE
Definition: page_buffer.h:41
SCAN_CODE heap_next(THREAD_ENTRY *thread_p, const HFID *hfid, OID *class_oid, OID *next_oid, RECDES *recdes, HEAP_SCANCACHE *scan_cache, int ispeeking)
Definition: heap_file.c:18622
void push_task(entry_workpool *worker_pool_arg, entry_task *exec_p)
void retire_system_worker()
static int btree_load_check_fk(THREAD_ENTRY *thread_p, const LOAD_ARGS *load_args_local, const SORT_ARGS *sort_args_local)
Definition: btree_load.c:3801
int qexec_clear_func_pred(THREAD_ENTRY *thread_p, func_pred *fpr)
DB_VALUE_COMPARE_RESULT index_cmpdisk(const void *memptr1, const void *memptr2, const tp_domain *domain, int do_coercion, int total_order, int *start_colp) const
int logtb_delete_global_unique_stats(THREAD_ENTRY *thread_p, BTID *btid)
int or_pad(OR_BUF *buf, int length)
DB_VALUE_COMPARE_RESULT
Definition: dbtype_def.h:199
BTID_INT * btid
Definition: btree_load.c:102
int cur_key_len
Definition: btree_load.c:111
TP_DOMAIN * key_type
Definition: btree.h:124
int btree_read_record(THREAD_ENTRY *thread_p, BTID_INT *btid, PAGE_PTR pgptr, RECDES *rec, DB_VALUE *key, void *rec_header, BTREE_NODE_TYPE node_type, bool *clear_key, int *offset, int copy_key, BTREE_SCAN *bts)
Definition: btree.c:4233
HFID * hfids
Definition: btree_load.c:62
static void btree_rv_save_root_head(int null_delta, int oid_delta, int key_delta, RECDES *recdes)
Definition: btree_load.c:612
short key_len
Definition: btree.h:106
#define PEEK
Definition: file_io.h:74
LOG_TRAN_BTID_UNIQUE_STATS * logtb_tran_find_btid_stats(THREAD_ENTRY *thread_p, const BTID *btid, bool create)
int n_nulls
Definition: btree_load.c:72
#define VPID_SET_NULL(vpid_ptr)
Definition: dbtype_def.h:906
BTREE_NODE_SPLIT_INFO split_info
Definition: btree_load.h:196
css_conn_entry * m_conn
Definition: btree_load.c:170
bool is_logging_configured(const int logging_flag)
int btree_node_header_redo_log(THREAD_ENTRY *thread_p, VFID *vfid, PAGE_PTR page_ptr)
Definition: btree_load.c:436
#define VACUUM_LOG_ADD_DROPPED_FILE_UNDO
Definition: vacuum.h:79
int stx_map_stream_to_filter_pred(THREAD_ENTRY *thread_p, pred_expr_with_context **pred, char *pred_stream, int pred_stream_size)
VPID vpid_first_leaf
Definition: btree_load.c:140
std::atomic_bool m_has_error
Definition: btree_load.c:166
#define VFID_SET_NULL(vfid_ptr)
Definition: file_manager.h:65
const char ** p
Definition: dynamic_load.c:945
int logtb_tran_update_btid_unique_stats(THREAD_ENTRY *thread_p, const BTID *btid, int n_keys, int n_oids, int n_nulls)
int or_advance(OR_BUF *buf, int offset)
HEAP_CACHE_ATTRINFO attr_info
Definition: btree_load.c:71
int spage_insert_at(THREAD_ENTRY *thread_p, PAGE_PTR page_p, PGSLOTID slot_id, RECDES *record_descriptor_p)
HEAP_CACHE_ATTRINFO * cache_pred
Definition: xasl.h:1061
static int btree_is_slot_visible(THREAD_ENTRY *thread_p, BTID_INT *btid, PAGE_PTR pg_ptr, MVCC_SNAPSHOT *mvcc_snapshot, int slot_id, bool *is_slot_visible)
Definition: btree_load.c:4385
int btree_packed_mvccinfo_size(BTREE_MVCC_INFO *mvcc_info)
Definition: btree.c:21394
int get_disk_size_of_value(const DB_VALUE *value) const
#define BTREE_SET_UNIQUE_VIOLATION_ERROR(THREAD, KEY, OID, C_OID, BTID, BTNM)
Definition: btree.h:96
#define BTREE_INIT_SCAN(bts)
Definition: btree.h:253
XASL_UNPACK_INFO * unpack_info
Definition: xasl.h:1062
RECDES ovf_recdes
Definition: btree_load.c:107
int pr_midxkey_element_disk_size(char *mem, DB_DOMAIN *domain)
int ib_thread_count