diff options
Diffstat (limited to 'innobase/btr')
-rw-r--r-- | innobase/btr/Makefile.am | 25 | ||||
-rw-r--r-- | innobase/btr/btr0btr.c | 2404 | ||||
-rw-r--r-- | innobase/btr/btr0cur.c | 2288 | ||||
-rw-r--r-- | innobase/btr/btr0pcur.c | 474 | ||||
-rw-r--r-- | innobase/btr/btr0sea.c | 1436 | ||||
-rw-r--r-- | innobase/btr/makefilewin | 16 | ||||
-rw-r--r-- | innobase/btr/ts/isql.c | 312 | ||||
-rw-r--r-- | innobase/btr/ts/makefile | 16 | ||||
-rw-r--r-- | innobase/btr/ts/trash/TSIT.C | 483 | ||||
-rw-r--r-- | innobase/btr/ts/trash/tsbtrold5.c | 798 | ||||
-rw-r--r-- | innobase/btr/ts/trash/tscli.c | 2263 | ||||
-rw-r--r-- | innobase/btr/ts/tsbtr97.c | 5080 | ||||
-rw-r--r-- | innobase/btr/ts/tsbtrfull.c | 4925 | ||||
-rw-r--r-- | innobase/btr/ts/tsbtrins.c | 802 | ||||
-rw-r--r-- | innobase/btr/ts/tscli.c | 3380 | ||||
-rw-r--r-- | innobase/btr/ts/tsrecv.c | 4909 | ||||
-rw-r--r-- | innobase/btr/ts/tsrecv97.c | 4909 | ||||
-rw-r--r-- | innobase/btr/ts/tss.c | 397 | ||||
-rw-r--r-- | innobase/btr/ts/tssrv.c | 535 |
19 files changed, 35452 insertions, 0 deletions
diff --git a/innobase/btr/Makefile.am b/innobase/btr/Makefile.am new file mode 100644 index 00000000000..d62316f0544 --- /dev/null +++ b/innobase/btr/Makefile.am @@ -0,0 +1,25 @@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# & Innobase Oy +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +include ../include/Makefile.i + +libs_LIBRARIES = libbtr.a + +libbtr_a_SOURCES = btr0btr.c btr0cur.c btr0pcur.c btr0sea.c + +EXTRA_PROGRAMS = + diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c new file mode 100644 index 00000000000..63e70eb1b83 --- /dev/null +++ b/innobase/btr/btr0btr.c @@ -0,0 +1,2404 @@ +/****************************************************** +The B-tree + +(c) 1994-1996 Innobase Oy + +Created 6/2/1994 Heikki Tuuri +*******************************************************/ + +#include "btr0btr.h" + +#ifdef UNIV_NONINL +#include "btr0btr.ic" +#endif + +#include "fsp0fsp.h" +#include "page0page.h" +#include "btr0cur.h" +#include "btr0sea.h" +#include "btr0pcur.h" +#include "rem0cmp.h" +#include "lock0lock.h" +#include "ibuf0ibuf.h" + +/* +Node pointers +------------- +Leaf pages of a B-tree contain the index records stored in the +tree. On levels n > 0 we store 'node pointers' to pages on level +n - 1. For each page there is exactly one node pointer stored: +thus the our tree is an ordinary B-tree, not a B-link tree. + +A node pointer contains a prefix P of an index record. The prefix +is long enough so that it determines an index record uniquely. +The file page number of the child page is added as the last +field. To the child page we can store node pointers or index records +which are >= P in the alphabetical order, but < P1 if there is +a next node pointer on the level, and P1 is its prefix. + +If a node pointer with a prefix P points to a non-leaf child, +then the leftmost record in the child must have the same +prefix P. If it points to a leaf node, the child is not required +to contain any record with a prefix equal to P. The leaf case +is decided this way to allow arbitrary deletions in a leaf node +without touching upper levels of the tree. + +We have predefined a special minimum record which we +define as the smallest record in any alphabetical order. +A minimum record is denoted by setting a bit in the record +header. A minimum record acts as the prefix of a node pointer +which points to a leftmost node on any level of the tree. + +File page allocation +-------------------- +In the root node of a B-tree there are two file segment headers. +The leaf pages of a tree are allocated from one file segment, to +make them consecutive on disk if possible. From the other file segment +we allocate pages for the non-leaf levels of the tree. +*/ + +/* If this many inserts occur sequentially, it affects page split */ +#define BTR_PAGE_SEQ_INSERT_LIMIT 5 + +/****************************************************************** +Creates a new index page to the tree (not the root, and also not +used in page reorganization). */ +static +void +btr_page_create( +/*============*/ + page_t* page, /* in: page to be created */ + dict_tree_t* tree, /* in: index tree */ + mtr_t* mtr); /* in: mtr */ +/****************************************************************** +Allocates a new file page to be used in an index tree. */ +static +page_t* +btr_page_alloc( +/*===========*/ + /* out: new allocated page, + x-latched */ + dict_tree_t* tree, /* in: index tree */ + ulint hint_page_no, /* in: hint of a good page */ + byte file_direction, /* in: direction where a possible + page split is made */ + ulint level, /* in: level where the page is placed + in the tree */ + mtr_t* mtr); /* in: mtr */ +/****************************************************************** +Frees a file page used in an index tree. */ +static +void +btr_page_free( +/*==========*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in, own: page to be freed */ + mtr_t* mtr); /* in: mtr */ +/****************************************************************** +Sets the child node file address in a node pointer. */ +UNIV_INLINE +void +btr_node_ptr_set_child_page_no( +/*===========================*/ + rec_t* rec, /* in: node pointer record */ + ulint page_no, /* in: child node address */ + mtr_t* mtr); /* in: mtr */ +/**************************************************************** +Returns the upper level node pointer to a page. It is assumed that +mtr holds an x-latch on the tree. */ +static +rec_t* +btr_page_get_father_node_ptr( +/*=========================*/ + /* out: pointer to node pointer record */ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page: must contain at least one + user record */ + mtr_t* mtr); /* in: mtr */ +/***************************************************************** +Empties an index page. */ +static +void +btr_page_empty( +/*===========*/ + page_t* page, /* in: page to be emptied */ + mtr_t* mtr); /* in: mtr */ +/***************************************************************** +Returns TRUE if the insert fits on the appropriate half-page +with the chosen split_rec. */ +static +ibool +btr_page_insert_fits( +/*=================*/ + /* out: TRUE if fits */ + btr_cur_t* cursor, /* in: cursor at which insert + should be made */ + rec_t* split_rec, /* in: suggestion for first record + on upper half-page, or NULL if + tuple should be first */ + dtuple_t* tuple); /* in: tuple to insert */ + +/****************************************************************** +Gets the root node of a tree and x-latches it. */ +static +page_t* +btr_root_get( +/*=========*/ + /* out: root page, x-latched */ + dict_tree_t* tree, /* in: index tree */ + mtr_t* mtr) /* in: mtr */ +{ + ulint space; + ulint root_page_no; + page_t* root; + + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), MTR_MEMO_X_LOCK) + || mtr_memo_contains(mtr, dict_tree_get_lock(tree), MTR_MEMO_S_LOCK)); + + space = dict_tree_get_space(tree); + root_page_no = dict_tree_get_page(tree); + + root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr); + + return(root); +} + +/***************************************************************** +Gets pointer to the previous user record in the tree. It is assumed that +the caller has appropriate latches on the page and its neighbor. */ + +rec_t* +btr_get_prev_user_rec( +/*==================*/ + /* out: previous user record, NULL if there is none */ + rec_t* rec, /* in: record on leaf level */ + mtr_t* mtr) /* in: mtr holding a latch on the page, and if + needed, also to the previous page */ +{ + page_t* page; + page_t* prev_page; + ulint prev_page_no; + rec_t* prev_rec; + ulint space; + + page = buf_frame_align(rec); + + if (page_get_infimum_rec(page) != rec) { + + prev_rec = page_rec_get_prev(rec); + + if (page_get_infimum_rec(page) != prev_rec) { + + return(prev_rec); + } + } + + prev_page_no = btr_page_get_prev(page, mtr); + space = buf_frame_get_space_id(page); + + if (prev_page_no != FIL_NULL) { + + prev_page = buf_page_get_with_no_latch(space, prev_page_no, + mtr); + /* The caller must already have a latch to the brother */ + ut_ad((mtr_memo_contains(mtr, buf_block_align(prev_page), + MTR_MEMO_PAGE_S_FIX)) + || (mtr_memo_contains(mtr, buf_block_align(prev_page), + MTR_MEMO_PAGE_X_FIX))); + + prev_rec = page_rec_get_prev(page_get_supremum_rec(prev_page)); + + return(prev_rec); + } + + return(NULL); +} + +/***************************************************************** +Gets pointer to the next user record in the tree. It is assumed that the +caller has appropriate latches on the page and its neighbor. */ + +rec_t* +btr_get_next_user_rec( +/*==================*/ + /* out: next user record, NULL if there is none */ + rec_t* rec, /* in: record on leaf level */ + mtr_t* mtr) /* in: mtr holding a latch on the page, and if + needed, also to the next page */ +{ + page_t* page; + page_t* next_page; + ulint next_page_no; + rec_t* next_rec; + ulint space; + + page = buf_frame_align(rec); + + if (page_get_supremum_rec(page) != rec) { + + next_rec = page_rec_get_next(rec); + + if (page_get_supremum_rec(page) != next_rec) { + + return(next_rec); + } + } + + next_page_no = btr_page_get_next(page, mtr); + space = buf_frame_get_space_id(page); + + if (next_page_no != FIL_NULL) { + + next_page = buf_page_get_with_no_latch(space, next_page_no, + mtr); + /* The caller must already have a latch to the brother */ + ut_ad((mtr_memo_contains(mtr, buf_block_align(next_page), + MTR_MEMO_PAGE_S_FIX)) + || (mtr_memo_contains(mtr, buf_block_align(next_page), + MTR_MEMO_PAGE_X_FIX))); + + next_rec = page_rec_get_next(page_get_infimum_rec(next_page)); + + return(next_rec); + } + + return(NULL); +} + +/****************************************************************** +Creates a new index page to the tree (not the root, and also not used in +page reorganization). */ +static +void +btr_page_create( +/*============*/ + page_t* page, /* in: page to be created */ + dict_tree_t* tree, /* in: index tree */ + mtr_t* mtr) /* in: mtr */ +{ + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + page_create(page, mtr); + + btr_page_set_index_id(page, tree->id, mtr); +} + +/****************************************************************** +Allocates a new file page to be used in an ibuf tree. Takes the page from +the free list of the tree, which must contain pages! */ +static +page_t* +btr_page_alloc_for_ibuf( +/*====================*/ + /* out: new allocated page, x-latched */ + dict_tree_t* tree, /* in: index tree */ + mtr_t* mtr) /* in: mtr */ +{ + fil_addr_t node_addr; + page_t* root; + page_t* new_page; + + root = btr_root_get(tree, mtr); + + node_addr = flst_get_first(root + PAGE_HEADER + + PAGE_BTR_IBUF_FREE_LIST, mtr); + ut_a(node_addr.page != FIL_NULL); + + new_page = buf_page_get(dict_tree_get_space(tree), node_addr.page, + RW_X_LATCH, mtr); + buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW); + + flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, + new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, + mtr); + ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr)); + + return(new_page); +} + +/****************************************************************** +Allocates a new file page to be used in an index tree. NOTE: we assume +that the caller has made the reservation for free extents! */ +static +page_t* +btr_page_alloc( +/*===========*/ + /* out: new allocated page, x-latched */ + dict_tree_t* tree, /* in: index tree */ + ulint hint_page_no, /* in: hint of a good page */ + byte file_direction, /* in: direction where a possible + page split is made */ + ulint level, /* in: level where the page is placed + in the tree */ + mtr_t* mtr) /* in: mtr */ +{ + fseg_header_t* seg_header; + page_t* root; + page_t* new_page; + ulint new_page_no; + + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + if (tree->type & DICT_IBUF) { + + return(btr_page_alloc_for_ibuf(tree, mtr)); + } + + root = btr_root_get(tree, mtr); + + if (level == 0) { + seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; + } else { + seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; + } + + /* Parameter TRUE below states that the caller has made the + reservation for free extents, and thus we know that a page can + be allocated: */ + + new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, + file_direction, TRUE, mtr); + ut_a(new_page_no != FIL_NULL); + + new_page = buf_page_get(dict_tree_get_space(tree), new_page_no, + RW_X_LATCH, mtr); + buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW); + + return(new_page); +} + +/****************************************************************** +Gets the number of pages in a B-tree. */ + +ulint +btr_get_size( +/*=========*/ + /* out: number of pages */ + dict_index_t* index, /* in: index */ + ulint flag) /* in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ +{ + fseg_header_t* seg_header; + page_t* root; + ulint n; + ulint dummy; + mtr_t mtr; + + mtr_start(&mtr); + + mtr_s_lock(dict_tree_get_lock(index->tree), &mtr); + + root = btr_root_get(index->tree, &mtr); + + if (flag == BTR_N_LEAF_PAGES) { + seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; + + fseg_n_reserved_pages(seg_header, &n, &mtr); + + } else if (flag == BTR_TOTAL_SIZE) { + seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; + + n = fseg_n_reserved_pages(seg_header, &dummy, &mtr); + + seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; + + n += fseg_n_reserved_pages(seg_header, &dummy, &mtr); + } else { + ut_a(0); + } + + mtr_commit(&mtr); + + return(n); +} + +/****************************************************************** +Frees a page used in an ibuf tree. Puts the page to the free list of the +ibuf tree. */ +static +void +btr_page_free_for_ibuf( +/*===================*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page to be freed, x-latched */ + mtr_t* mtr) /* in: mtr */ +{ + page_t* root; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + root = btr_root_get(tree, mtr); + + flst_add_first(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, + page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr); + + ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr)); +} + +/****************************************************************** +Frees a file page used in an index tree. */ +static +void +btr_page_free( +/*==========*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page to be freed, x-latched */ + mtr_t* mtr) /* in: mtr */ +{ + fseg_header_t* seg_header; + page_t* root; + ulint space; + ulint page_no; + ulint level; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + /* The page gets invalid for optimistic searches: increment the frame + modify clock */ + + buf_frame_modify_clock_inc(page); + + if (tree->type & DICT_IBUF) { + + btr_page_free_for_ibuf(tree, page, mtr); + + return; + } + + root = btr_root_get(tree, mtr); + + level = btr_page_get_level(page, mtr); + + if (level == 0) { + seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; + } else { + seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; + } + + space = buf_frame_get_space_id(page); + page_no = buf_frame_get_page_no(page); + + fseg_free_page(seg_header, space, page_no, mtr); +} + +/****************************************************************** +Sets the child node file address in a node pointer. */ +UNIV_INLINE +void +btr_node_ptr_set_child_page_no( +/*===========================*/ + rec_t* rec, /* in: node pointer record */ + ulint page_no, /* in: child node address */ + mtr_t* mtr) /* in: mtr */ +{ + ulint n_fields; + byte* field; + ulint len; + + ut_ad(0 < btr_page_get_level(buf_frame_align(rec), mtr)); + + n_fields = rec_get_n_fields(rec); + + /* The child address is in the last field */ + field = rec_get_nth_field(rec, n_fields - 1, &len); + + ut_ad(len == 4); + + mlog_write_ulint(field, page_no, MLOG_4BYTES, mtr); +} + +/**************************************************************** +Returns the child page of a node pointer and x-latches it. */ +static +page_t* +btr_node_ptr_get_child( +/*===================*/ + /* out: child page, x-latched */ + rec_t* node_ptr, /* in: node pointer */ + mtr_t* mtr) /* in: mtr */ +{ + ulint page_no; + ulint space; + page_t* page; + + space = buf_frame_get_space_id(node_ptr); + page_no = btr_node_ptr_get_child_page_no(node_ptr); + + page = btr_page_get(space, page_no, RW_X_LATCH, mtr); + + return(page); +} + +/**************************************************************** +Returns the upper level node pointer to a page. It is assumed that mtr holds +an x-latch on the tree. */ +static +rec_t* +btr_page_get_father_for_rec( +/*========================*/ + /* out: pointer to node pointer record, + its page x-latched */ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page: must contain at least one + user record */ + rec_t* user_rec,/* in: user_record on page */ + mtr_t* mtr) /* in: mtr */ +{ + mem_heap_t* heap; + dtuple_t* tuple; + btr_cur_t cursor; + rec_t* node_ptr; + + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + ut_ad(user_rec != page_get_supremum_rec(page)); + ut_ad(user_rec != page_get_infimum_rec(page)); + + ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page)); + + heap = mem_heap_create(100); + + tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap); + + /* In the following, we choose just any index from the tree as the + first parameter for btr_cur_search_to_nth_level. */ + + btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes), + btr_page_get_level(page, mtr) + 1, + tuple, PAGE_CUR_LE, + BTR_CONT_MODIFY_TREE, &cursor, 0, mtr); + + node_ptr = btr_cur_get_rec(&cursor); + + ut_ad(btr_node_ptr_get_child_page_no(node_ptr) == + buf_frame_get_page_no(page)); + mem_heap_free(heap); + + return(node_ptr); +} + +/**************************************************************** +Returns the upper level node pointer to a page. It is assumed that +mtr holds an x-latch on the tree. */ +static +rec_t* +btr_page_get_father_node_ptr( +/*=========================*/ + /* out: pointer to node pointer record */ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page: must contain at least one + user record */ + mtr_t* mtr) /* in: mtr */ +{ + return(btr_page_get_father_for_rec(tree, page, + page_rec_get_next(page_get_infimum_rec(page)), mtr)); +} + +/**************************************************************** +Creates the root node for a new index tree. */ + +ulint +btr_create( +/*=======*/ + /* out: page number of the created root, FIL_NULL if + did not succeed */ + ulint type, /* in: type of the index */ + ulint space, /* in: space where created */ + dulint index_id,/* in: index id */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + ulint page_no; + buf_frame_t* ibuf_hdr_frame; + buf_frame_t* frame; + page_t* page; + + /* Create the two new segments (one, in the case of an ibuf tree) for + the index tree; the segment headers are put on the allocated root page + (for an ibuf tree, not in the root, but on a separate ibuf header + page) */ + + if (type & DICT_IBUF) { + /* Allocate first the ibuf header page */ + ibuf_hdr_frame = fseg_create(space, 0, + IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); + + buf_page_dbg_add_level(ibuf_hdr_frame, SYNC_TREE_NODE_NEW); + + ut_ad(buf_frame_get_page_no(ibuf_hdr_frame) + == IBUF_HEADER_PAGE_NO); + /* Allocate then the next page to the segment: it will be the + tree root page */ + + page_no = fseg_alloc_free_page( + ibuf_hdr_frame + IBUF_HEADER + + IBUF_TREE_SEG_HEADER, IBUF_TREE_ROOT_PAGE_NO, + FSP_UP, mtr); + ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO); + + frame = buf_page_get(space, page_no, RW_X_LATCH, mtr); + } else { + frame = fseg_create(space, 0, PAGE_HEADER + PAGE_BTR_SEG_TOP, + mtr); + } + + if (frame == NULL) { + + return(FIL_NULL); + } + + page_no = buf_frame_get_page_no(frame); + + buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW); + + if (type & DICT_IBUF) { + /* It is an insert buffer tree: initialize the free list */ + + ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO); + + flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr); + } else { + /* It is a non-ibuf tree: create a file segment for leaf + pages */ + fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF, + mtr); + /* The fseg create acquires a second latch on the page, + therefore we must declare it: */ + buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW); + } + + /* Create a new index page on the the allocated segment page */ + page = page_create(frame, mtr); + + /* Set the index id of the page */ + btr_page_set_index_id(page, index_id, mtr); + + /* Set the level of the new index page */ + btr_page_set_level(page, 0, mtr); + + /* Set the next node and previous node fields */ + btr_page_set_next(page, FIL_NULL, mtr); + btr_page_set_prev(page, FIL_NULL, mtr); + + /* We reset the free bits for the page to allow creation of several + trees in the same mtr, otherwise the latch on a bitmap page would + prevent it because of the latching order */ + + ibuf_reset_free_bits_with_type(type, page); + + /* In the following assertion we test that two records of maximum + allowed size fit on the root page: this fact is needed to ensure + correctness of split algorithms */ + + ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE); + + return(page_no); +} + +/**************************************************************** +Frees a B-tree except the root page, which MUST be freed after this +by calling btr_free_root. */ + +void +btr_free_but_not_root( +/*==================*/ + ulint space, /* in: space where created */ + ulint root_page_no) /* in: root page number */ +{ + ibool finished; + page_t* root; + mtr_t mtr; + +leaf_loop: + mtr_start(&mtr); + + root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr); + + /* NOTE: page hash indexes are dropped when a page is freed inside + fsp0fsp. */ + + finished = fseg_free_step( + root + PAGE_HEADER + PAGE_BTR_SEG_LEAF, &mtr); + mtr_commit(&mtr); + + if (!finished) { + + goto leaf_loop; + } +top_loop: + mtr_start(&mtr); + + root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr); + + finished = fseg_free_step_not_header( + root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr); + mtr_commit(&mtr); + + if (!finished) { + + goto top_loop; + } +} + +/**************************************************************** +Frees the B-tree root page. Other tree MUST already have been freed. */ + +void +btr_free_root( +/*==========*/ + ulint space, /* in: space where created */ + ulint root_page_no, /* in: root page number */ + mtr_t* mtr) /* in: a mini-transaction which has already + been started */ +{ + ibool finished; + page_t* root; + + root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr); + + btr_search_drop_page_hash_index(root); +top_loop: + finished = fseg_free_step( + root + PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr); + if (!finished) { + + goto top_loop; + } +} + +/***************************************************************** +Reorganizes an index page. */ + +void +btr_page_reorganize_low( +/*====================*/ + ibool low, /* in: TRUE if locks should not be updated, i.e., + there cannot exist locks on the page */ + page_t* page, /* in: page to be reorganized */ + mtr_t* mtr) /* in: mtr */ +{ + page_t* new_page; + ulint log_mode; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + /* Write the log record */ + mlog_write_initial_log_record(page, MLOG_PAGE_REORGANIZE, mtr); + + /* Turn logging off */ + log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); + + new_page = buf_frame_alloc(); + + /* Copy the old page to temporary space */ + buf_frame_copy(new_page, page); + + btr_search_drop_page_hash_index(page); + + /* Recreate the page: note that global data on page (possible + segment headers, next page-field, etc.) is preserved intact */ + + page_create(page, mtr); + + /* Copy the records from the temporary space to the recreated page; + do not copy the lock bits yet */ + + page_copy_rec_list_end_no_locks(page, new_page, + page_get_infimum_rec(new_page), mtr); + /* Copy max trx id to recreated page */ + page_set_max_trx_id(page, page_get_max_trx_id(new_page)); + + if (!low) { + /* Update the record lock bitmaps */ + lock_move_reorganize_page(page, new_page); + } + + buf_frame_free(new_page); + + /* Restore logging mode */ + mtr_set_log_mode(mtr, log_mode); +} + +/***************************************************************** +Reorganizes an index page. */ + +void +btr_page_reorganize( +/*================*/ + page_t* page, /* in: page to be reorganized */ + mtr_t* mtr) /* in: mtr */ +{ + btr_page_reorganize_low(FALSE, page, mtr); +} + +/*************************************************************** +Parses a redo log record of reorganizing a page. */ + +byte* +btr_parse_page_reorganize( +/*======================*/ + /* out: end of log record or NULL */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + page_t* page, /* in: page or NULL */ + mtr_t* mtr) /* in: mtr or NULL */ +{ + ut_ad(ptr && end_ptr); + + /* The record is empty, except for the record initial part */ + + if (page) { + btr_page_reorganize_low(TRUE, page, mtr); + } + + return(ptr); +} + +/***************************************************************** +Empties an index page. */ +static +void +btr_page_empty( +/*===========*/ + page_t* page, /* in: page to be emptied */ + mtr_t* mtr) /* in: mtr */ +{ + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + btr_search_drop_page_hash_index(page); + + /* Recreate the page: note that global data on page (possible + segment headers, next page-field, etc.) is preserved intact */ + + page_create(page, mtr); +} + +/***************************************************************** +Makes tree one level higher by splitting the root, and inserts +the tuple. It is assumed that mtr contains an x-latch on the tree. +NOTE that the operation of this function must always succeed, +we cannot reverse it: therefore enough free disk space must be +guaranteed to be available before this function is called. */ + +rec_t* +btr_root_raise_and_insert( +/*======================*/ + /* out: inserted record */ + btr_cur_t* cursor, /* in: cursor at which to insert: must be + on the root page; when the function returns, + the cursor is positioned on the predecessor + of the inserted record */ + dtuple_t* tuple, /* in: tuple to insert */ + mtr_t* mtr) /* in: mtr */ +{ + dict_tree_t* tree; + page_t* root; + page_t* new_page; + ulint new_page_no; + rec_t* rec; + mem_heap_t* heap; + dtuple_t* node_ptr; + ulint level; + rec_t* node_ptr_rec; + page_cur_t* page_cursor; + + root = btr_cur_get_page(cursor); + tree = btr_cur_get_tree(cursor); + + ut_ad(dict_tree_get_page(tree) == buf_frame_get_page_no(root)); + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(root), + MTR_MEMO_PAGE_X_FIX)); + btr_search_drop_page_hash_index(root); + + /* Allocate a new page to the tree. Root splitting is done by first + moving the root records to the new page, emptying the root, putting + a node pointer to the new page, and then splitting the new page. */ + + new_page = btr_page_alloc(tree, 0, FSP_NO_DIR, + btr_page_get_level(root, mtr), mtr); + + btr_page_create(new_page, tree, mtr); + + level = btr_page_get_level(root, mtr); + + /* Set the levels of the new index page and root page */ + btr_page_set_level(new_page, level, mtr); + btr_page_set_level(root, level + 1, mtr); + + /* Set the next node and previous node fields of new page */ + btr_page_set_next(new_page, FIL_NULL, mtr); + btr_page_set_prev(new_page, FIL_NULL, mtr); + + /* Move the records from root to the new page */ + + page_move_rec_list_end(new_page, root, page_get_infimum_rec(root), + mtr); + /* If this is a pessimistic insert which is actually done to + perform a pessimistic update then we have stored the lock + information of the record to be inserted on the infimum of the + root page: we cannot discard the lock structs on the root page */ + + lock_update_root_raise(new_page, root); + + /* Create a memory heap where the node pointer is stored */ + heap = mem_heap_create(100); + + rec = page_rec_get_next(page_get_infimum_rec(new_page)); + new_page_no = buf_frame_get_page_no(new_page); + + /* Build the node pointer (= node key and page address) for the + child */ + + node_ptr = dict_tree_build_node_ptr(tree, rec, new_page_no, heap); + + /* Reorganize the root to get free space */ + btr_page_reorganize(root, mtr); + + page_cursor = btr_cur_get_page_cur(cursor); + + /* Insert node pointer to the root */ + + page_cur_set_before_first(root, page_cursor); + + node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr, mtr); + + ut_ad(node_ptr_rec); + + /* The node pointer must be marked as the predefined minimum record, + as there is no lower alphabetical limit to records in the leftmost + node of a level: */ + + btr_set_min_rec_mark(node_ptr_rec, mtr); + + /* Free the memory heap */ + mem_heap_free(heap); + + /* We play safe and reset the free bits for the new page */ + +/* printf("Root raise new page no %lu\n", + buf_frame_get_page_no(new_page)); */ + + ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), + new_page); + /* Reposition the cursor to the child node */ + page_cur_search(new_page, tuple, PAGE_CUR_LE, page_cursor); + + /* Split the child and insert tuple */ + return(btr_page_split_and_insert(cursor, tuple, mtr)); +} + +/***************************************************************** +Decides if the page should be split at the convergence point of inserts +converging to the left. */ + +ibool +btr_page_get_split_rec_to_left( +/*===========================*/ + /* out: TRUE if split recommended */ + btr_cur_t* cursor, /* in: cursor at which to insert */ + rec_t** split_rec) /* out: if split recommended, + the first record on upper half page, + or NULL if tuple to be inserted should + be first */ +{ + page_t* page; + rec_t* insert_point; + rec_t* infimum; + + page = btr_cur_get_page(cursor); + insert_point = btr_cur_get_rec(cursor); + + if ((page_header_get_ptr(page, PAGE_LAST_INSERT) + == page_rec_get_next(insert_point)) + && (page_header_get_field(page, PAGE_DIRECTION) == PAGE_LEFT) + && ((page_header_get_field(page, PAGE_N_DIRECTION) + >= BTR_PAGE_SEQ_INSERT_LIMIT) + || (page_header_get_field(page, PAGE_N_DIRECTION) + 1 + >= page_get_n_recs(page)))) { + + infimum = page_get_infimum_rec(page); + + if ((infimum != insert_point) + && (page_rec_get_next(infimum) != insert_point)) { + + *split_rec = insert_point; + } else { + *split_rec = page_rec_get_next(insert_point); + } + + return(TRUE); + } + + return(FALSE); +} + +/***************************************************************** +Decides if the page should be split at the convergence point of inserts +converging to the right. */ + +ibool +btr_page_get_split_rec_to_right( +/*============================*/ + /* out: TRUE if split recommended */ + btr_cur_t* cursor, /* in: cursor at which to insert */ + rec_t** split_rec) /* out: if split recommended, + the first record on upper half page, + or NULL if tuple to be inserted should + be first */ +{ + page_t* page; + rec_t* insert_point; + rec_t* supremum; + + page = btr_cur_get_page(cursor); + insert_point = btr_cur_get_rec(cursor); + + if ((page_header_get_ptr(page, PAGE_LAST_INSERT) == insert_point) + && (page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT) + && ((page_header_get_field(page, PAGE_N_DIRECTION) + >= BTR_PAGE_SEQ_INSERT_LIMIT) + || (page_header_get_field(page, PAGE_N_DIRECTION) + 1 + >= page_get_n_recs(page)))) { + + supremum = page_get_supremum_rec(page); + + if ((page_rec_get_next(insert_point) != supremum) + && (page_rec_get_next(page_rec_get_next(insert_point)) + != supremum) + && (page_rec_get_next(page_rec_get_next( + page_rec_get_next(insert_point))) + != supremum)) { + + /* If there are >= 3 user records up from the insert + point, split all but 2 off */ + + *split_rec = page_rec_get_next(page_rec_get_next( + page_rec_get_next(insert_point))); + } else { + /* Else split at inserted record */ + *split_rec = NULL; + } + + return(TRUE); + } + + return(FALSE); +} + +/***************************************************************** +Calculates a split record such that the tuple will certainly fit on +its half-page when the split is performed. We assume in this function +only that the cursor page has at least one user record. */ +static +rec_t* +btr_page_get_sure_split_rec( +/*========================*/ + /* out: split record, or NULL if + tuple will be the first record on + upper half-page */ + btr_cur_t* cursor, /* in: cursor at which insert + should be made */ + dtuple_t* tuple) /* in: tuple to insert */ +{ + page_t* page; + ulint insert_size; + ulint free_space; + ulint total_data; + ulint total_n_recs; + ulint total_space; + ulint incl_data; + rec_t* ins_rec; + rec_t* rec; + rec_t* next_rec; + ulint n; + + page = btr_cur_get_page(cursor); + + insert_size = rec_get_converted_size(tuple); + free_space = page_get_free_space_of_empty(); + + /* free_space is now the free space of a created new page */ + + total_data = page_get_data_size(page) + insert_size; + total_n_recs = page_get_n_recs(page) + 1; + ut_ad(total_n_recs >= 2); + total_space = total_data + page_dir_calc_reserved_space(total_n_recs); + + n = 0; + incl_data = 0; + ins_rec = btr_cur_get_rec(cursor); + rec = page_get_infimum_rec(page); + + /* We start to include records to the left half, and when the + space reserved by them exceeds half of total_space, then if + the included records fit on the left page, they will be put there + if something was left over also for the right page, + otherwise the last included record will be the first on the right + half page */ + + for (;;) { + /* Decide the next record to include */ + if (rec == ins_rec) { + rec = NULL; /* NULL denotes that tuple is + now included */ + } else if (rec == NULL) { + rec = page_rec_get_next(ins_rec); + } else { + rec = page_rec_get_next(rec); + } + + if (rec == NULL) { + /* Include tuple */ + incl_data += insert_size; + } else { + incl_data += rec_get_size(rec); + } + + n++; + + if (incl_data + page_dir_calc_reserved_space(n) + >= total_space / 2) { + + if (incl_data + page_dir_calc_reserved_space(n) + <= free_space) { + /* The next record will be the first on + the right half page if it is not the + supremum record of page */ + + if (rec == ins_rec) { + next_rec = NULL; + } else if (rec == NULL) { + next_rec = page_rec_get_next(ins_rec); + } else { + next_rec = page_rec_get_next(rec); + } + if (next_rec != page_get_supremum_rec(page)) { + + return(next_rec); + } + } + + return(rec); + } + } +} + +/***************************************************************** +Returns TRUE if the insert fits on the appropriate half-page with the +chosen split_rec. */ +static +ibool +btr_page_insert_fits( +/*=================*/ + /* out: TRUE if fits */ + btr_cur_t* cursor, /* in: cursor at which insert + should be made */ + rec_t* split_rec, /* in: suggestion for first record + on upper half-page, or NULL if + tuple to be inserted should be first */ + dtuple_t* tuple) /* in: tuple to insert */ +{ + page_t* page; + ulint insert_size; + ulint free_space; + ulint total_data; + ulint total_n_recs; + rec_t* rec; + rec_t* end_rec; + + page = btr_cur_get_page(cursor); + + insert_size = rec_get_converted_size(tuple); + free_space = page_get_free_space_of_empty(); + + /* free_space is now the free space of a created new page */ + + total_data = page_get_data_size(page) + insert_size; + total_n_recs = page_get_n_recs(page) + 1; + + /* We determine which records (from rec to end_rec, not including + end_rec) will end up on the other half page from tuple when it is + inserted. */ + + if (split_rec == NULL) { + rec = page_rec_get_next(page_get_infimum_rec(page)); + end_rec = page_rec_get_next(btr_cur_get_rec(cursor)); + + } else if (cmp_dtuple_rec(tuple, split_rec) >= 0) { + + rec = page_rec_get_next(page_get_infimum_rec(page)); + end_rec = split_rec; + } else { + rec = split_rec; + end_rec = page_get_supremum_rec(page); + } + + if (total_data + page_dir_calc_reserved_space(total_n_recs) + <= free_space) { + + /* Ok, there will be enough available space on the + half page where the tuple is inserted */ + + return(TRUE); + } + + while (rec != end_rec) { + /* In this loop we calculate the amount of reserved + space after rec is removed from page. */ + + total_data -= rec_get_size(rec); + total_n_recs--; + + if (total_data + page_dir_calc_reserved_space(total_n_recs) + <= free_space) { + + /* Ok, there will be enough available space on the + half page where the tuple is inserted */ + + return(TRUE); + } + + rec = page_rec_get_next(rec); + } + + return(FALSE); +} + +/*********************************************************** +Inserts a data tuple to a tree on a non-leaf level. It is assumed +that mtr holds an x-latch on the tree. */ + +void +btr_insert_on_non_leaf_level( +/*=========================*/ + dict_tree_t* tree, /* in: tree */ + ulint level, /* in: level, must be > 0 */ + dtuple_t* tuple, /* in: the record to be inserted */ + mtr_t* mtr) /* in: mtr */ +{ + btr_cur_t cursor; + ulint err; + rec_t* rec; + + ut_ad(level > 0); + + /* In the following, choose just any index from the tree as the + first parameter for btr_cur_search_to_nth_level. */ + + btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes), + level, tuple, PAGE_CUR_LE, + BTR_CONT_MODIFY_TREE, + &cursor, 0, mtr); + + err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG + | BTR_KEEP_SYS_FLAG + | BTR_NO_UNDO_LOG_FLAG, + &cursor, tuple, + &rec, NULL, mtr); + ut_a(err == DB_SUCCESS); +} + +/****************************************************************** +Attaches the halves of an index page on the appropriate level in an +index tree. */ +static +void +btr_attach_half_pages( +/*==================*/ + dict_tree_t* tree, /* in: the index tree */ + page_t* page, /* in: page to be split */ + rec_t* split_rec, /* in: first record on upper + half page */ + page_t* new_page, /* in: the new half page */ + ulint direction, /* in: FSP_UP or FSP_DOWN */ + mtr_t* mtr) /* in: mtr */ +{ + ulint space; + rec_t* node_ptr; + page_t* prev_page; + page_t* next_page; + ulint prev_page_no; + ulint next_page_no; + ulint level; + page_t* lower_page; + page_t* upper_page; + ulint lower_page_no; + ulint upper_page_no; + dtuple_t* node_ptr_upper; + mem_heap_t* heap; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(new_page), + MTR_MEMO_PAGE_X_FIX)); + + /* Based on split direction, decide upper and lower pages */ + if (direction == FSP_DOWN) { + + lower_page_no = buf_frame_get_page_no(new_page); + upper_page_no = buf_frame_get_page_no(page); + lower_page = new_page; + upper_page = page; + + /* Look from the tree for the node pointer to page */ + node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); + + /* Replace the address of the old child node (= page) with the + address of the new lower half */ + + btr_node_ptr_set_child_page_no(node_ptr, lower_page_no, mtr); + } else { + lower_page_no = buf_frame_get_page_no(page); + upper_page_no = buf_frame_get_page_no(new_page); + lower_page = page; + upper_page = new_page; + } + + /* Create a memory heap where the data tuple is stored */ + heap = mem_heap_create(100); + + /* Get the level of the split pages */ + level = btr_page_get_level(page, mtr); + + /* Build the node pointer (= node key and page address) for the upper + half */ + + node_ptr_upper = dict_tree_build_node_ptr(tree, split_rec, + upper_page_no, heap); + + /* Insert it next to the pointer to the lower half. Note that this + may generate recursion leading to a split on the higher level. */ + + btr_insert_on_non_leaf_level(tree, level + 1, node_ptr_upper, mtr); + + /* Free the memory heap */ + mem_heap_free(heap); + + /* Get the previous and next pages of page */ + + prev_page_no = btr_page_get_prev(page, mtr); + next_page_no = btr_page_get_next(page, mtr); + space = buf_frame_get_space_id(page); + + /* Update page links of the level */ + + if (prev_page_no != FIL_NULL) { + + prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr); + + btr_page_set_next(prev_page, lower_page_no, mtr); + } + + if (next_page_no != FIL_NULL) { + + next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr); + + btr_page_set_prev(next_page, upper_page_no, mtr); + } + + btr_page_set_prev(lower_page, prev_page_no, mtr); + btr_page_set_next(lower_page, upper_page_no, mtr); + btr_page_set_level(lower_page, level, mtr); + + btr_page_set_prev(upper_page, lower_page_no, mtr); + btr_page_set_next(upper_page, next_page_no, mtr); + btr_page_set_level(upper_page, level, mtr); +} + +/***************************************************************** +Splits an index page to halves and inserts the tuple. It is assumed +that mtr holds an x-latch to the index tree. NOTE: the tree x-latch +is released within this function! NOTE that the operation of this +function must always succeed, we cannot reverse it: therefore +enough free disk space must be guaranteed to be available before +this function is called. */ + +rec_t* +btr_page_split_and_insert( +/*======================*/ + /* out: inserted record; NOTE: the tree + x-latch is released! NOTE: 2 free disk + pages must be available! */ + btr_cur_t* cursor, /* in: cursor at which to insert; when the + function returns, the cursor is positioned + on the predecessor of the inserted record */ + dtuple_t* tuple, /* in: tuple to insert */ + mtr_t* mtr) /* in: mtr */ +{ + dict_tree_t* tree; + page_t* page; + ulint page_no; + byte direction; + ulint hint_page_no; + page_t* new_page; + rec_t* split_rec; + page_t* left_page; + page_t* right_page; + page_t* insert_page; + page_cur_t* page_cursor; + rec_t* first_rec; + byte* buf; + rec_t* move_limit; + ibool insert_will_fit; + ulint n_iterations = 0; + rec_t* rec; +func_start: + tree = btr_cur_get_tree(cursor); + + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + ut_ad(rw_lock_own(dict_tree_get_lock(tree), RW_LOCK_EX)); + + page = btr_cur_get_page(cursor); + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + ut_ad(page_get_n_recs(page) >= 2); + + page_no = buf_frame_get_page_no(page); + + /* 1. Decide the split record; split_rec == NULL means that the + tuple to be inserted should be the first record on the upper + half-page */ + + if (n_iterations > 0) { + direction = FSP_UP; + hint_page_no = page_no + 1; + split_rec = btr_page_get_sure_split_rec(cursor, tuple); + + } else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) { + direction = FSP_UP; + hint_page_no = page_no + 1; + + } else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) { + direction = FSP_DOWN; + hint_page_no = page_no - 1; + } else { + direction = FSP_UP; + hint_page_no = page_no + 1; + split_rec = page_get_middle_rec(page); + } + + /* 2. Allocate a new page to the tree */ + new_page = btr_page_alloc(tree, hint_page_no, direction, + btr_page_get_level(page, mtr), mtr); + btr_page_create(new_page, tree, mtr); + + /* 3. Calculate the first record on the upper half-page, and the + first record (move_limit) on original page which ends up on the + upper half */ + + if (split_rec != NULL) { + first_rec = split_rec; + move_limit = split_rec; + } else { + buf = mem_alloc(rec_get_converted_size(tuple)); + + first_rec = rec_convert_dtuple_to_rec(buf, tuple); + move_limit = page_rec_get_next(btr_cur_get_rec(cursor)); + } + + /* 4. Do first the modifications in the tree structure */ + + btr_attach_half_pages(tree, page, first_rec, new_page, direction, mtr); + + if (split_rec == NULL) { + mem_free(buf); + } + + /* If the split is made on the leaf level and the insert will fit + on the appropriate half-page, we may release the tree x-latch. + We can then move the records after releasing the tree latch, + thus reducing the tree latch contention. */ + + insert_will_fit = btr_page_insert_fits(cursor, split_rec, tuple); + + if (insert_will_fit && (btr_page_get_level(page, mtr) == 0)) { + + mtr_memo_release(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK); + } + + /* 5. Move then the records to the new page */ + if (direction == FSP_DOWN) { +/* printf("Split left\n"); */ + + page_move_rec_list_start(new_page, page, move_limit, mtr); + left_page = new_page; + right_page = page; + + lock_update_split_left(right_page, left_page); + } else { +/* printf("Split right\n"); */ + + page_move_rec_list_end(new_page, page, move_limit, mtr); + left_page = page; + right_page = new_page; + + lock_update_split_right(right_page, left_page); + } + + /* 6. The split and the tree modification is now completed. Decide the + page where the tuple should be inserted */ + + if (split_rec == NULL) { + insert_page = right_page; + + } else if (cmp_dtuple_rec(tuple, first_rec) >= 0) { + + insert_page = right_page; + } else { + insert_page = left_page; + } + + /* 7. Reposition the cursor for insert and try insertion */ + page_cursor = btr_cur_get_page_cur(cursor); + + page_cur_search(insert_page, tuple, PAGE_CUR_LE, page_cursor); + + rec = page_cur_tuple_insert(page_cursor, tuple, mtr); + + if (rec != NULL) { + /* Insert fit on the page: update the free bits for the + left and right pages in the same mtr */ + + ibuf_update_free_bits_for_two_pages_low(cursor->index, + left_page, + right_page, mtr); + /* printf("Split and insert done %lu %lu\n", + buf_frame_get_page_no(left_page), + buf_frame_get_page_no(right_page)); */ + return(rec); + } + + /* 8. If insert did not fit, try page reorganization */ + + btr_page_reorganize(insert_page, mtr); + + page_cur_search(insert_page, tuple, PAGE_CUR_LE, page_cursor); + rec = page_cur_tuple_insert(page_cursor, tuple, mtr); + + if (rec == NULL) { + /* The insert did not fit on the page: loop back to the + start of the function for a new split */ + + /* We play safe and reset the free bits for new_page */ + ibuf_reset_free_bits(cursor->index, new_page); + + /* printf("Split second round %lu\n", + buf_frame_get_page_no(page)); */ + n_iterations++; + ut_ad(n_iterations < 2); + ut_ad(!insert_will_fit); + + goto func_start; + } + + /* Insert fit on the page: update the free bits for the + left and right pages in the same mtr */ + + ibuf_update_free_bits_for_two_pages_low(cursor->index, left_page, + right_page, mtr); + /* printf("Split and insert done %lu %lu\n", + buf_frame_get_page_no(left_page), + buf_frame_get_page_no(right_page)); */ + + ut_ad(page_validate(left_page, UT_LIST_GET_FIRST(tree->tree_indexes))); + ut_ad(page_validate(right_page, UT_LIST_GET_FIRST(tree->tree_indexes))); + + return(rec); +} + +/***************************************************************** +Removes a page from the level list of pages. */ +static +void +btr_level_list_remove( +/*==================*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page to remove */ + mtr_t* mtr) /* in: mtr */ +{ + ulint space; + ulint prev_page_no; + page_t* prev_page; + ulint next_page_no; + page_t* next_page; + + ut_ad(tree && page && mtr); + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + /* Get the previous and next page numbers of page */ + + prev_page_no = btr_page_get_prev(page, mtr); + next_page_no = btr_page_get_next(page, mtr); + space = buf_frame_get_space_id(page); + + /* Update page links of the level */ + + if (prev_page_no != FIL_NULL) { + + prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr); + + btr_page_set_next(prev_page, next_page_no, mtr); + } + + if (next_page_no != FIL_NULL) { + + next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr); + + btr_page_set_prev(next_page, prev_page_no, mtr); + } +} + +/******************************************************************** +Writes the redo log record for setting an index record as the predefined +minimum record. */ +UNIV_INLINE +void +btr_set_min_rec_mark_log( +/*=====================*/ + rec_t* rec, /* in: record */ + mtr_t* mtr) /* in: mtr */ +{ + mlog_write_initial_log_record(rec, MLOG_REC_MIN_MARK, mtr); + + /* Write rec offset as a 2-byte ulint */ + mlog_catenate_ulint(mtr, rec - buf_frame_align(rec), MLOG_2BYTES); +} + +/******************************************************************** +Parses the redo log record for setting an index record as the predefined +minimum record. */ + +byte* +btr_parse_set_min_rec_mark( +/*=======================*/ + /* out: end of log record or NULL */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + page_t* page, /* in: page or NULL */ + mtr_t* mtr) /* in: mtr or NULL */ +{ + rec_t* rec; + + if (end_ptr < ptr + 2) { + + return(NULL); + } + + if (page) { + rec = page + mach_read_from_2(ptr); + + btr_set_min_rec_mark(rec, mtr); + } + + return(ptr + 2); +} + +/******************************************************************** +Sets a record as the predefined minimum record. */ + +void +btr_set_min_rec_mark( +/*=================*/ + rec_t* rec, /* in: record */ + mtr_t* mtr) /* in: mtr */ +{ + ulint info_bits; + + info_bits = rec_get_info_bits(rec); + + rec_set_info_bits(rec, info_bits | REC_INFO_MIN_REC_FLAG); + + btr_set_min_rec_mark_log(rec, mtr); +} + +/***************************************************************** +Deletes on the upper level the node pointer to a page. */ + +void +btr_node_ptr_delete( +/*================*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page whose node pointer is deleted */ + mtr_t* mtr) /* in: mtr */ +{ + rec_t* node_ptr; + btr_cur_t cursor; + ibool compressed; + ulint err; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + /* Delete node pointer on father page */ + + node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); + + btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr, + &cursor); + compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, mtr); + + ut_a(err == DB_SUCCESS); + + if (!compressed) { + btr_cur_compress_if_useful(&cursor, mtr); + } +} + +/***************************************************************** +If page is the only on its level, this function moves its records to the +father page, thus reducing the tree height. */ +static +void +btr_lift_page_up( +/*=============*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page which is the only on its level; + must not be empty: use + btr_discard_only_page_on_level if the last + record from the page should be removed */ + mtr_t* mtr) /* in: mtr */ +{ + rec_t* node_ptr; + page_t* father_page; + ulint page_level; + + ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL); + ut_ad(btr_page_get_next(page, mtr) == FIL_NULL); + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); + father_page = buf_frame_align(node_ptr); + + page_level = btr_page_get_level(page, mtr); + + btr_search_drop_page_hash_index(page); + + /* Make the father empty */ + btr_page_empty(father_page, mtr); + + /* Move records to the father */ + page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page), + mtr); + lock_update_copy_and_discard(father_page, page); + + btr_page_set_level(father_page, page_level, mtr); + + /* Free the file page */ + btr_page_free(tree, page, mtr); + + /* We play safe and reset the free bits for the father */ + ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), + father_page); + ut_ad(page_validate(father_page, + UT_LIST_GET_FIRST(tree->tree_indexes))); + ut_ad(btr_check_node_ptr(tree, father_page, mtr)); +} + +/***************************************************************** +Tries to merge the page first to the left immediate brother if such a +brother exists, and the node pointers to the current page and to the brother +reside on the same page. If the left brother does not satisfy these +conditions, looks at the right brother. If the page is the only one on that +level lifts the records of the page to the father page, thus reducing the +tree height. It is assumed that mtr holds an x-latch on the tree and on the +page. If cursor is on the leaf level, mtr must also hold x-latches to the +brothers, if they exist. NOTE: it is assumed that the caller has reserved +enough free extents so that the compression will always succeed if done! */ + +void +btr_compress( +/*=========*/ + btr_cur_t* cursor, /* in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr) /* in: mtr */ +{ + dict_tree_t* tree; + ulint space; + ulint left_page_no; + ulint right_page_no; + page_t* merge_page; + page_t* father_page; + ibool is_left; + page_t* page; + rec_t* orig_pred; + rec_t* orig_succ; + rec_t* node_ptr; + ulint data_size; + ulint n_recs; + ulint max_ins_size; + ulint max_ins_size_reorg; + ulint level; + + page = btr_cur_get_page(cursor); + tree = btr_cur_get_tree(cursor); + + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + level = btr_page_get_level(page, mtr); + space = dict_tree_get_space(tree); + + left_page_no = btr_page_get_prev(page, mtr); + right_page_no = btr_page_get_next(page, mtr); + +/* printf("Merge left page %lu right %lu \n", left_page_no, + right_page_no); */ + + node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); + father_page = buf_frame_align(node_ptr); + + /* Decide the page to which we try to merge and which will inherit + the locks */ + + if (left_page_no != FIL_NULL) { + + is_left = TRUE; + merge_page = btr_page_get(space, left_page_no, RW_X_LATCH, + mtr); + } else if (right_page_no != FIL_NULL) { + + is_left = FALSE; + merge_page = btr_page_get(space, right_page_no, RW_X_LATCH, + mtr); + } else { + /* The page is the only one on the level, lift the records + to the father */ + btr_lift_page_up(tree, page, mtr); + + return; + } + + n_recs = page_get_n_recs(page); + data_size = page_get_data_size(page); + + max_ins_size_reorg = page_get_max_insert_size_after_reorganize( + merge_page, n_recs); + if (data_size > max_ins_size_reorg) { + + /* No space for merge */ + + return; + } + + ut_ad(page_validate(merge_page, cursor->index)); + + max_ins_size = page_get_max_insert_size(merge_page, n_recs); + + if (data_size > max_ins_size) { + + /* We have to reorganize merge_page */ + + btr_page_reorganize(merge_page, mtr); + + ut_ad(page_validate(merge_page, cursor->index)); + ut_ad(page_get_max_insert_size(merge_page, n_recs) + == max_ins_size_reorg); + } + + btr_search_drop_page_hash_index(page); + + /* Remove the page from the level list */ + btr_level_list_remove(tree, page, mtr); + + if (is_left) { + btr_node_ptr_delete(tree, page, mtr); + } else { + /* Replace the address of the old child node (= page) with the + address of the merge page to the right */ + + btr_node_ptr_set_child_page_no(node_ptr, right_page_no, mtr); + + btr_node_ptr_delete(tree, merge_page, mtr); + } + + /* Move records to the merge page */ + if (is_left) { + orig_pred = page_rec_get_prev( + page_get_supremum_rec(merge_page)); + page_copy_rec_list_start(merge_page, page, + page_get_supremum_rec(page), mtr); + + lock_update_merge_left(merge_page, orig_pred, page); + } else { + orig_succ = page_rec_get_next( + page_get_infimum_rec(merge_page)); + page_copy_rec_list_end(merge_page, page, + page_get_infimum_rec(page), mtr); + + lock_update_merge_right(orig_succ, page); + } + + /* We have added new records to merge_page: update its free bits */ + ibuf_update_free_bits_if_full(cursor->index, merge_page, + UNIV_PAGE_SIZE, ULINT_UNDEFINED); + + ut_ad(page_validate(merge_page, cursor->index)); + + /* Free the file page */ + btr_page_free(tree, page, mtr); + + ut_ad(btr_check_node_ptr(tree, merge_page, mtr)); +} + +/***************************************************************** +Discards a page that is the only page on its level. */ +static +void +btr_discard_only_page_on_level( +/*===========================*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: page which is the only on its level */ + mtr_t* mtr) /* in: mtr */ +{ + rec_t* node_ptr; + page_t* father_page; + ulint page_level; + + ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL); + ut_ad(btr_page_get_next(page, mtr) == FIL_NULL); + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + btr_search_drop_page_hash_index(page); + + node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); + father_page = buf_frame_align(node_ptr); + + page_level = btr_page_get_level(page, mtr); + + lock_update_discard(page_get_supremum_rec(father_page), page); + + btr_page_set_level(father_page, page_level, mtr); + + /* Free the file page */ + btr_page_free(tree, page, mtr); + + if (buf_frame_get_page_no(father_page) == dict_tree_get_page(tree)) { + /* The father is the root page */ + + btr_page_empty(father_page, mtr); + + /* We play safe and reset the free bits for the father */ + ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), + father_page); + } else { + ut_ad(page_get_n_recs(father_page) == 1); + + btr_discard_only_page_on_level(tree, father_page, mtr); + } +} + +/***************************************************************** +Discards a page from a B-tree. This is used to remove the last record from +a B-tree page: the whole page must be removed at the same time. This cannot +be used for the root page, which is allowed to be empty. */ + +void +btr_discard_page( +/*=============*/ + btr_cur_t* cursor, /* in: cursor on the page to discard: not on + the root page */ + mtr_t* mtr) /* in: mtr */ +{ + dict_tree_t* tree; + ulint space; + ulint left_page_no; + ulint right_page_no; + page_t* merge_page; + ibool is_left; + page_t* page; + rec_t* node_ptr; + + page = btr_cur_get_page(cursor); + tree = btr_cur_get_tree(cursor); + + ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page)); + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + space = dict_tree_get_space(tree); + + /* Decide the page which will inherit the locks */ + + left_page_no = btr_page_get_prev(page, mtr); + right_page_no = btr_page_get_next(page, mtr); + + if (left_page_no != FIL_NULL) { + is_left = TRUE; + merge_page = btr_page_get(space, left_page_no, RW_X_LATCH, + mtr); + } else if (right_page_no != FIL_NULL) { + is_left = FALSE; + merge_page = btr_page_get(space, right_page_no, RW_X_LATCH, + mtr); + } else { + btr_discard_only_page_on_level(tree, page, mtr); + + return; + } + + btr_search_drop_page_hash_index(page); + + if ((left_page_no == FIL_NULL) + && (btr_page_get_level(page, mtr) > 0)) { + + /* We have to mark the leftmost node pointer on the right + side page as the predefined minimum record */ + + node_ptr = page_rec_get_next(page_get_infimum_rec(merge_page)); + + ut_ad(node_ptr != page_get_supremum_rec(merge_page)); + + btr_set_min_rec_mark(node_ptr, mtr); + } + + btr_node_ptr_delete(tree, page, mtr); + + /* Remove the page from the level list */ + btr_level_list_remove(tree, page, mtr); + + if (is_left) { + lock_update_discard(page_get_supremum_rec(merge_page), page); + } else { + lock_update_discard(page_rec_get_next( + page_get_infimum_rec(merge_page)), page); + } + + /* Free the file page */ + btr_page_free(tree, page, mtr); + + ut_ad(btr_check_node_ptr(tree, merge_page, mtr)); +} + +/***************************************************************** +Prints size info of a B-tree. */ + +void +btr_print_size( +/*===========*/ + dict_tree_t* tree) /* in: index tree */ +{ + page_t* root; + fseg_header_t* seg; + mtr_t mtr; + + if (tree->type & DICT_IBUF) { + printf( + "Sorry, cannot print info of an ibuf tree: use ibuf functions\n"); + + return; + } + + mtr_start(&mtr); + + root = btr_root_get(tree, &mtr); + + seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; + + printf("INFO OF THE NON-LEAF PAGE SEGMENT\n"); + fseg_print(seg, &mtr); + + if (!(tree->type & DICT_UNIVERSAL)) { + + seg = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; + + printf("INFO OF THE LEAF PAGE SEGMENT\n"); + fseg_print(seg, &mtr); + } + + mtr_commit(&mtr); +} + +/**************************************************************** +Prints recursively index tree pages. */ +static +void +btr_print_recursive( +/*================*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: index page */ + ulint width, /* in: print this many entries from start + and end */ + mtr_t* mtr) /* in: mtr */ +{ + page_cur_t cursor; + ulint n_recs; + ulint i = 0; + mtr_t mtr2; + rec_t* node_ptr; + page_t* child; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + printf("NODE ON LEVEL %lu page number %lu\n", + btr_page_get_level(page, mtr), buf_frame_get_page_no(page)); + + page_print(page, width, width); + + n_recs = page_get_n_recs(page); + + page_cur_set_before_first(page, &cursor); + page_cur_move_to_next(&cursor); + + while (!page_cur_is_after_last(&cursor)) { + + if (0 == btr_page_get_level(page, mtr)) { + + /* If this is the leaf level, do nothing */ + + } else if ((i <= width) || (i >= n_recs - width)) { + + mtr_start(&mtr2); + + node_ptr = page_cur_get_rec(&cursor); + + child = btr_node_ptr_get_child(node_ptr, &mtr2); + + btr_print_recursive(tree, child, width, &mtr2); + mtr_commit(&mtr2); + } + + page_cur_move_to_next(&cursor); + i++; + } +} + +/****************************************************************** +Prints directories and other info of all nodes in the tree. */ + +void +btr_print_tree( +/*===========*/ + dict_tree_t* tree, /* in: tree */ + ulint width) /* in: print this many entries from start + and end */ +{ + mtr_t mtr; + page_t* root; + + printf("--------------------------\n"); + printf("INDEX TREE PRINT\n"); + + mtr_start(&mtr); + + root = btr_root_get(tree, &mtr); + + btr_print_recursive(tree, root, width, &mtr); + + mtr_commit(&mtr); + + btr_validate_tree(tree); +} + +/**************************************************************** +Checks that the node pointer to a page is appropriate. */ + +ibool +btr_check_node_ptr( +/*===============*/ + /* out: TRUE */ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: index page */ + mtr_t* mtr) /* in: mtr */ +{ + mem_heap_t* heap; + rec_t* node_ptr; + dtuple_t* node_ptr_tuple; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + if (dict_tree_get_page(tree) == buf_frame_get_page_no(page)) { + + return(TRUE); + } + + node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); + + if (btr_page_get_level(page, mtr) == 0) { + + return(TRUE); + } + + heap = mem_heap_create(256); + + node_ptr_tuple = dict_tree_build_node_ptr( + tree, + page_rec_get_next(page_get_infimum_rec(page)), + 0, heap); + + ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr) == 0); + + mem_heap_free(heap); + + return(TRUE); +} + +/**************************************************************** +Validates index tree level. */ +static +void +btr_validate_level( +/*===============*/ + dict_tree_t* tree, /* in: index tree */ + ulint level) /* in: level number */ +{ + ulint space; + mtr_t mtr; + page_t* page; + page_t* right_page; + page_t* father_page; + page_t* right_father_page; + rec_t* node_ptr; + rec_t* right_node_ptr; + ulint right_page_no; + ulint left_page_no; + page_cur_t cursor; + mem_heap_t* heap; + dtuple_t* node_ptr_tuple; + + mtr_start(&mtr); + + page = btr_root_get(tree, &mtr); + + space = buf_frame_get_space_id(page); + + while (level != btr_page_get_level(page, &mtr)) { + + ut_a(btr_page_get_level(page, &mtr) > 0); + + page_cur_set_before_first(page, &cursor); + page_cur_move_to_next(&cursor); + + node_ptr = page_cur_get_rec(&cursor); + page = btr_node_ptr_get_child(node_ptr, &mtr); + } + + /* Now we are on the desired level */ +loop: + mtr_x_lock(dict_tree_get_lock(tree), &mtr); + + /* Check ordering of records */ + page_validate(page, UT_LIST_GET_FIRST(tree->tree_indexes)); + + ut_a(btr_page_get_level(page, &mtr) == level); + + right_page_no = btr_page_get_next(page, &mtr); + left_page_no = btr_page_get_prev(page, &mtr); + + ut_a((page_get_n_recs(page) > 0) + || ((level == 0) && + (buf_frame_get_page_no(page) == dict_tree_get_page(tree)))); + + if (right_page_no != FIL_NULL) { + + right_page = btr_page_get(space, right_page_no, RW_X_LATCH, + &mtr); + ut_a(cmp_rec_rec(page_rec_get_prev(page_get_supremum_rec(page)), + page_rec_get_next(page_get_infimum_rec(right_page)), + UT_LIST_GET_FIRST(tree->tree_indexes)) < 0); + } + + if ((level > 0) && (left_page_no == FIL_NULL)) { + ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits( + page_rec_get_next(page_get_infimum_rec(page)))); + } + + if (buf_frame_get_page_no(page) != dict_tree_get_page(tree)) { + + /* Check father node pointers */ + + node_ptr = btr_page_get_father_node_ptr(tree, page, &mtr); + + ut_a(node_ptr == btr_page_get_father_for_rec(tree, page, + page_rec_get_prev(page_get_supremum_rec(page)), &mtr)); + + father_page = buf_frame_align(node_ptr); + + if (btr_page_get_level(page, &mtr) > 0) { + heap = mem_heap_create(256); + + node_ptr_tuple = dict_tree_build_node_ptr( + tree, + page_rec_get_next( + page_get_infimum_rec(page)), + 0, heap); + ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr) == 0); + mem_heap_free(heap); + } + + if (left_page_no == FIL_NULL) { + ut_a(node_ptr == page_rec_get_next( + page_get_infimum_rec(father_page))); + ut_a(btr_page_get_prev(father_page, &mtr) == FIL_NULL); + } + + if (right_page_no == FIL_NULL) { + ut_a(node_ptr == page_rec_get_prev( + page_get_supremum_rec(father_page))); + ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL); + } + + if (right_page_no != FIL_NULL) { + + right_node_ptr = btr_page_get_father_node_ptr(tree, + right_page, &mtr); + if (page_rec_get_next(node_ptr) != + page_get_supremum_rec(father_page)) { + + ut_a(right_node_ptr == + page_rec_get_next(node_ptr)); + } else { + right_father_page = buf_frame_align( + right_node_ptr); + + ut_a(right_node_ptr == page_rec_get_next( + page_get_infimum_rec( + right_father_page))); + ut_a(buf_frame_get_page_no(right_father_page) + == btr_page_get_next(father_page, &mtr)); + } + } + } + + mtr_commit(&mtr); + + if (right_page_no != FIL_NULL) { + mtr_start(&mtr); + + page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr); + + goto loop; + } +} + +/****************************************************************** +Checks the consistency of an index tree. */ + +void +btr_validate_tree( +/*==============*/ + dict_tree_t* tree) /* in: tree */ +{ + mtr_t mtr; + page_t* root; + ulint i; + ulint n; + + mtr_start(&mtr); + mtr_x_lock(dict_tree_get_lock(tree), &mtr); + + root = btr_root_get(tree, &mtr); + n = btr_page_get_level(root, &mtr); + + for (i = 0; i <= n; i++) { + + btr_validate_level(tree, n - i); + } + + mtr_commit(&mtr); +} diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c new file mode 100644 index 00000000000..c5ea8232a37 --- /dev/null +++ b/innobase/btr/btr0cur.c @@ -0,0 +1,2288 @@ +/****************************************************** +The index tree cursor + +All changes that row operations make to a B-tree or the records +there must go through this module! Undo log records are written here +of every modify or insert of a clustered index record. + + NOTE!!! +To make sure we do not run out of disk space during a pessimistic +insert or update, we have to reserve 2 x the height of the index tree +many pages in the tablespace before we start the operation, because +if leaf splitting has been started, it is difficult to undo, except +by crashing the database and doing a roll-forward. + +(c) 1994-1996 Innobase Oy + +Created 10/16/1994 Heikki Tuuri +*******************************************************/ + +#include "btr0cur.h" + +#ifdef UNIV_NONINL +#include "btr0cur.ic" +#endif + +#include "page0page.h" +#include "rem0rec.h" +#include "btr0btr.h" +#include "btr0sea.h" +#include "row0upd.h" +#include "trx0rec.h" +#include "que0que.h" +#include "row0row.h" +#include "srv0srv.h" +#include "ibuf0ibuf.h" +#include "lock0lock.h" + +ulint btr_cur_rnd = 0; + +ulint btr_cur_n_non_sea = 0; + +/* In the optimistic insert, if the insert does not fit, but this much space +can be released by page reorganize, then it is reorganized */ + +#define BTR_CUR_PAGE_REORGANIZE_LIMIT (UNIV_PAGE_SIZE / 32) + +/* When estimating number of different kay values in an index sample +this many index pages */ +#define BTR_KEY_VAL_ESTIMATE_N_PAGES 8 + +/*********************************************************************** +Adds path information to the cursor for the current page, for which +the binary search has been performed. */ +static +void +btr_cur_add_path_info( +/*==================*/ + btr_cur_t* cursor, /* in: cursor positioned on a page */ + ulint height, /* in: height of the page in tree; + 0 means leaf node */ + ulint root_height); /* in: root node height in tree */ + +/*==================== B-TREE SEARCH =========================*/ + +/************************************************************************ +Latches the leaf page or pages requested. */ +static +void +btr_cur_latch_leaves( +/*=================*/ + dict_tree_t* tree, /* in: index tree */ + page_t* page, /* in: leaf page where the search + converged */ + ulint space, /* in: space id */ + ulint page_no, /* in: page number of the leaf */ + ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */ + btr_cur_t* cursor, /* in: cursor */ + mtr_t* mtr) /* in: mtr */ +{ + ulint left_page_no; + ulint right_page_no; + + ut_ad(tree && page && mtr); + + if (latch_mode == BTR_SEARCH_LEAF) { + + btr_page_get(space, page_no, RW_S_LATCH, mtr); + + } else if (latch_mode == BTR_MODIFY_LEAF) { + + btr_page_get(space, page_no, RW_X_LATCH, mtr); + + } else if (latch_mode == BTR_MODIFY_TREE) { + + /* x-latch also brothers from left to right */ + left_page_no = btr_page_get_prev(page, mtr); + + if (left_page_no != FIL_NULL) { + btr_page_get(space, left_page_no, RW_X_LATCH, mtr); + } + + btr_page_get(space, page_no, RW_X_LATCH, mtr); + + right_page_no = btr_page_get_next(page, mtr); + + if (right_page_no != FIL_NULL) { + btr_page_get(space, right_page_no, RW_X_LATCH, mtr); + } + + } else if (latch_mode == BTR_SEARCH_PREV) { + + /* s-latch also left brother */ + left_page_no = btr_page_get_prev(page, mtr); + + if (left_page_no != FIL_NULL) { + cursor->left_page = btr_page_get(space, left_page_no, + RW_S_LATCH, mtr); + } + + btr_page_get(space, page_no, RW_S_LATCH, mtr); + + } else if (latch_mode == BTR_MODIFY_PREV) { + + /* x-latch also left brother */ + left_page_no = btr_page_get_prev(page, mtr); + + if (left_page_no != FIL_NULL) { + cursor->left_page = btr_page_get(space, left_page_no, + RW_X_LATCH, mtr); + } + + btr_page_get(space, page_no, RW_X_LATCH, mtr); + } else { + ut_error; + } +} + +/************************************************************************ +Searches an index tree and positions a tree cursor on a given level. +NOTE: n_fields_cmp in tuple must be set so that it cannot be compared +to node pointer page number fields on the upper levels of the tree! +Note that if mode is PAGE_CUR_LE, which is used in inserts, then +cursor->up_match and cursor->low_match both will have sensible values. +If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */ + +void +btr_cur_search_to_nth_level( +/*========================*/ + dict_index_t* index, /* in: index */ + ulint level, /* in: the tree level of search */ + dtuple_t* tuple, /* in: data tuple; NOTE: n_fields_cmp in + tuple must be set so that it cannot get + compared to the node ptr page number field! */ + ulint mode, /* in: PAGE_CUR_L, ...; + NOTE that if the search is made using a unique + prefix of a record, mode should be + PAGE_CUR_LE, not PAGE_CUR_GE, as the latter + may end up on the previous page relative to the + record! Inserts should always be made using + PAGE_CUR_LE to search the position! */ + ulint latch_mode, /* in: BTR_SEARCH_LEAF, ..., ORed with + BTR_INSERT and BTR_ESTIMATE; + cursor->left_page is used to store a pointer + to the left neighbor page, in the cases + BTR_SEARCH_PREV and BTR_MODIFY_PREV */ + btr_cur_t* cursor, /* in/out: tree cursor; the cursor page is + s- or x-latched */ + ulint has_search_latch,/* in: info on the latch mode the + caller currently has on btr_search_latch: + RW_S_LATCH, or 0 */ + mtr_t* mtr) /* in: mtr */ +{ + dict_tree_t* tree; + page_cur_t* page_cursor; + page_t* page; + page_t* guess; + rec_t* node_ptr; + ulint page_no; + ulint space; + ulint up_match; + ulint up_bytes; + ulint low_match; + ulint low_bytes; + ulint height; + ulint savepoint; + ulint rw_latch; + ulint page_mode; + ulint insert_planned; + ulint buf_mode; + ulint estimate; + ulint root_height; +#ifdef BTR_CUR_ADAPT + btr_search_t* info; +#endif + /* Currently, PAGE_CUR_LE is the only search mode used for searches + ending to upper levels */ + + ut_ad(level == 0 || mode == PAGE_CUR_LE); + ut_ad(dict_tree_check_search_tuple(index->tree, tuple)); + ut_ad(!(index->type & DICT_IBUF) || ibuf_inside()); + ut_ad(dtuple_check_typed(tuple)); + +#ifdef UNIV_DEBUG + cursor->up_match = ULINT_UNDEFINED; + cursor->low_match = ULINT_UNDEFINED; +#endif + insert_planned = latch_mode & BTR_INSERT; + estimate = latch_mode & BTR_ESTIMATE; + latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE); + + ut_ad(!insert_planned || (mode == PAGE_CUR_LE)); + + cursor->flag = BTR_CUR_BINARY; + cursor->index = index; + +#ifndef BTR_CUR_ADAPT + guess = NULL; +#else + info = btr_search_get_info(index); + + guess = info->root_guess; + +#ifdef BTR_CUR_HASH_ADAPT + +#ifdef UNIV_SEARCH_PERF_STAT + info->n_searches++; +#endif + if (latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ + && !estimate + && btr_search_guess_on_hash(index, info, tuple, mode, + latch_mode, cursor, + has_search_latch, mtr)) { + + /* Search using the hash index succeeded */ + + ut_ad(cursor->up_match != ULINT_UNDEFINED + || mode != PAGE_CUR_GE); + ut_ad(cursor->up_match != ULINT_UNDEFINED + || mode != PAGE_CUR_LE); + ut_ad(cursor->low_match != ULINT_UNDEFINED + || mode != PAGE_CUR_LE); + return; + } +#endif +#endif + +#ifdef UNIV_SEARCH_PERF_STAT + btr_cur_n_non_sea++; +#endif + /* If the hash search did not succeed, do binary search down the + tree */ + + if (has_search_latch) { + /* Release possible search latch to obey latching order */ + rw_lock_s_unlock(&btr_search_latch); + } + + savepoint = mtr_set_savepoint(mtr); + + tree = index->tree; + + if (latch_mode == BTR_MODIFY_TREE) { + mtr_x_lock(dict_tree_get_lock(tree), mtr); + + } else if (latch_mode == BTR_CONT_MODIFY_TREE) { + /* Do nothing */ + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + } else { + mtr_s_lock(dict_tree_get_lock(tree), mtr); + } + + page_cursor = btr_cur_get_page_cur(cursor); + + space = dict_tree_get_space(tree); + page_no = dict_tree_get_page(tree); + + up_match = 0; + up_bytes = 0; + low_match = 0; + low_bytes = 0; + + height = ULINT_UNDEFINED; + rw_latch = RW_NO_LATCH; + buf_mode = BUF_GET; + + if (mode == PAGE_CUR_GE) { + page_mode = PAGE_CUR_L; + } else if (mode == PAGE_CUR_G) { + page_mode = PAGE_CUR_LE; + } else if (mode == PAGE_CUR_LE) { + page_mode = PAGE_CUR_LE; + } else { + ut_ad(mode == PAGE_CUR_L); + page_mode = PAGE_CUR_L; + } + + /* Loop and search until we arrive at the desired level */ + + for (;;) { + if ((height == 0) && (latch_mode <= BTR_MODIFY_LEAF)) { + + rw_latch = latch_mode; + + if (insert_planned && ibuf_should_try(index)) { + + /* Try insert to the insert buffer if the + page is not in the buffer pool */ + + buf_mode = BUF_GET_IF_IN_POOL; + } + } +retry_page_get: + page = buf_page_get_gen(space, page_no, rw_latch, guess, + buf_mode, +#ifdef UNIV_SYNC_DEBUG + __FILE__, __LINE__, +#endif + mtr); + + if (page == NULL) { + /* This must be a search to perform an insert; + try insert to the insert buffer */ + + ut_ad(buf_mode == BUF_GET_IF_IN_POOL); + ut_ad(insert_planned); + ut_ad(cursor->thr); + + if (ibuf_should_try(index) && + ibuf_insert(tuple, index, space, page_no, + cursor->thr)) { + /* Insertion to the insert buffer succeeded */ + cursor->flag = BTR_CUR_INSERT_TO_IBUF; + + return; + } + + /* Insert to the insert buffer did not succeed: + retry page get */ + + buf_mode = BUF_GET; + + goto retry_page_get; + } + +#ifdef UNIV_SYNC_DEBUG + if (rw_latch != RW_NO_LATCH) { + buf_page_dbg_add_level(page, SYNC_TREE_NODE); + } +#endif + ut_ad(0 == ut_dulint_cmp(tree->id, + btr_page_get_index_id(page))); + + if (height == ULINT_UNDEFINED) { + /* We are in the root node */ + + height = btr_page_get_level(page, mtr); + root_height = height; + cursor->tree_height = root_height + 1; +#ifdef BTR_CUR_ADAPT + if (page != guess) { + info->root_guess = page; + } +#endif + } + + if (height == 0) { + if (rw_latch == RW_NO_LATCH) { + + btr_cur_latch_leaves(tree, page, space, + page_no, latch_mode, cursor, + mtr); + } + + if ((latch_mode != BTR_MODIFY_TREE) + && (latch_mode != BTR_CONT_MODIFY_TREE)) { + + /* Release the tree s-latch */ + + mtr_release_s_latch_at_savepoint( + mtr, savepoint, + dict_tree_get_lock(tree)); + } + + page_mode = mode; + } + + page_cur_search_with_match(page, tuple, page_mode, &up_match, + &up_bytes, &low_match, &low_bytes, + page_cursor); + if (estimate) { + btr_cur_add_path_info(cursor, height, root_height); + } + + /* If this is the desired level, leave the loop */ + + if (level == height) { + + if (level > 0) { + /* x-latch the page */ + btr_page_get(space, page_no, RW_X_LATCH, mtr); + } + + break; + } + + ut_ad(height > 0); + + height--; + guess = NULL; + + node_ptr = page_cur_get_rec(page_cursor); + + /* Go to the child node */ + page_no = btr_node_ptr_get_child_page_no(node_ptr); + } + + if (level == 0) { + cursor->low_match = low_match; + cursor->low_bytes = low_bytes; + cursor->up_match = up_match; + cursor->up_bytes = up_bytes; + +#ifdef BTR_CUR_ADAPT + btr_search_info_update(index, cursor); +#endif + + ut_ad(cursor->up_match != ULINT_UNDEFINED + || mode != PAGE_CUR_GE); + ut_ad(cursor->up_match != ULINT_UNDEFINED + || mode != PAGE_CUR_LE); + ut_ad(cursor->low_match != ULINT_UNDEFINED + || mode != PAGE_CUR_LE); + } + + if (has_search_latch) { + + rw_lock_s_lock(&btr_search_latch); + } +} + +/********************************************************************* +Opens a cursor at either end of an index. */ + +void +btr_cur_open_at_index_side( +/*=======================*/ + ibool from_left, /* in: TRUE if open to the low end, + FALSE if to the high end */ + dict_index_t* index, /* in: index */ + ulint latch_mode, /* in: latch mode */ + btr_cur_t* cursor, /* in: cursor */ + mtr_t* mtr) /* in: mtr */ +{ + page_cur_t* page_cursor; + dict_tree_t* tree; + page_t* page; + ulint page_no; + ulint space; + ulint height; + ulint root_height; + rec_t* node_ptr; + ulint estimate; + + estimate = latch_mode & BTR_ESTIMATE; + latch_mode = latch_mode & ~BTR_ESTIMATE; + + tree = index->tree; + + if (latch_mode == BTR_MODIFY_TREE) { + mtr_x_lock(dict_tree_get_lock(tree), mtr); + } else { + mtr_s_lock(dict_tree_get_lock(tree), mtr); + } + + page_cursor = btr_cur_get_page_cur(cursor); + cursor->index = index; + + space = dict_tree_get_space(tree); + page_no = dict_tree_get_page(tree); + + height = ULINT_UNDEFINED; + + for (;;) { + page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL, + BUF_GET, +#ifdef UNIV_SYNC_DEBUG + __FILE__, __LINE__, +#endif + mtr); + ut_ad(0 == ut_dulint_cmp(tree->id, + btr_page_get_index_id(page))); + + if (height == ULINT_UNDEFINED) { + /* We are in the root node */ + + height = btr_page_get_level(page, mtr); + root_height = height; + } + + if (height == 0) { + btr_cur_latch_leaves(tree, page, space, page_no, + latch_mode, cursor, mtr); + } + + if (from_left) { + page_cur_set_before_first(page, page_cursor); + } else { + page_cur_set_after_last(page, page_cursor); + } + + if (estimate) { + btr_cur_add_path_info(cursor, height, root_height); + } + + if (height == 0) { + + break; + } + + ut_ad(height > 0); + + if (from_left) { + page_cur_move_to_next(page_cursor); + } else { + page_cur_move_to_prev(page_cursor); + } + + height--; + + node_ptr = page_cur_get_rec(page_cursor); + + /* Go to the child node */ + page_no = btr_node_ptr_get_child_page_no(node_ptr); + } +} + +/************************************************************************** +Positions a cursor at a randomly chosen position within a B-tree. */ + +void +btr_cur_open_at_rnd_pos( +/*====================*/ + dict_index_t* index, /* in: index */ + ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */ + btr_cur_t* cursor, /* in/out: B-tree cursor */ + mtr_t* mtr) /* in: mtr */ +{ + page_cur_t* page_cursor; + dict_tree_t* tree; + page_t* page; + ulint page_no; + ulint space; + ulint height; + rec_t* node_ptr; + + tree = index->tree; + + if (latch_mode == BTR_MODIFY_TREE) { + mtr_x_lock(dict_tree_get_lock(tree), mtr); + } else { + mtr_s_lock(dict_tree_get_lock(tree), mtr); + } + + page_cursor = btr_cur_get_page_cur(cursor); + cursor->index = index; + + space = dict_tree_get_space(tree); + page_no = dict_tree_get_page(tree); + + height = ULINT_UNDEFINED; + + for (;;) { + page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL, + BUF_GET, +#ifdef UNIV_SYNC_DEBUG + __FILE__, __LINE__, +#endif + mtr); + ut_ad(0 == ut_dulint_cmp(tree->id, + btr_page_get_index_id(page))); + + if (height == ULINT_UNDEFINED) { + /* We are in the root node */ + + height = btr_page_get_level(page, mtr); + } + + if (height == 0) { + btr_cur_latch_leaves(tree, page, space, page_no, + latch_mode, cursor, mtr); + } + + page_cur_open_on_rnd_user_rec(page, page_cursor); + + if (height == 0) { + + break; + } + + ut_ad(height > 0); + + height--; + + node_ptr = page_cur_get_rec(page_cursor); + + /* Go to the child node */ + page_no = btr_node_ptr_get_child_page_no(node_ptr); + } +} + +/*==================== B-TREE INSERT =========================*/ + +/***************************************************************** +Inserts a record if there is enough space, or if enough space can +be freed by reorganizing. Differs from _optimistic_insert because +no heuristics is applied to whether it pays to use CPU time for +reorganizing the page or not. */ +static +rec_t* +btr_cur_insert_if_possible( +/*=======================*/ + /* out: pointer to inserted record if succeed, + else NULL */ + btr_cur_t* cursor, /* in: cursor on page after which to insert; + cursor stays valid */ + dtuple_t* tuple, /* in: tuple to insert; the size info need not + have been stored to tuple */ + ibool* reorg, /* out: TRUE if reorganization occurred */ + mtr_t* mtr) /* in: mtr */ +{ + page_cur_t* page_cursor; + page_t* page; + rec_t* rec; + + ut_ad(dtuple_check_typed(tuple)); + + *reorg = FALSE; + + page = btr_cur_get_page(cursor); + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + page_cursor = btr_cur_get_page_cur(cursor); + + /* Now, try the insert */ + rec = page_cur_tuple_insert(page_cursor, tuple, mtr); + + if (!rec) { + /* If record did not fit, reorganize */ + + btr_page_reorganize(page, mtr); + + *reorg = TRUE; + + page_cur_search(page, tuple, PAGE_CUR_LE, page_cursor); + + rec = page_cur_tuple_insert(page_cursor, tuple, mtr); + } + + return(rec); +} + +/***************************************************************** +For an insert, checks the locks and does the undo logging if desired. */ +UNIV_INLINE +ulint +btr_cur_ins_lock_and_undo( +/*======================*/ + /* out: DB_SUCCESS, DB_WAIT_LOCK, + DB_FAIL, or error number */ + ulint flags, /* in: undo logging and locking flags: if + not zero, the parameters index and thr + should be specified */ + btr_cur_t* cursor, /* in: cursor on page after which to insert */ + dtuple_t* entry, /* in: entry to insert */ + que_thr_t* thr, /* in: query thread or NULL */ + ibool* inherit)/* out: TRUE if the inserted new record maybe + should inherit LOCK_GAP type locks from the + successor record */ +{ + dict_index_t* index; + ulint err; + rec_t* rec; + dulint roll_ptr; + + /* Check if we have to wait for a lock: enqueue an explicit lock + request if yes */ + + rec = btr_cur_get_rec(cursor); + index = cursor->index; + + err = lock_rec_insert_check_and_lock(flags, rec, index, thr, inherit); + + if (err != DB_SUCCESS) { + + return(err); + } + + if ((index->type & DICT_CLUSTERED) && !(index->type & DICT_IBUF)) { + + err = trx_undo_report_row_operation(flags, TRX_UNDO_INSERT_OP, + thr, index, entry, NULL, 0, NULL, + &roll_ptr); + if (err != DB_SUCCESS) { + + return(err); + } + + /* Now we can fill in the roll ptr field in entry */ + + if (!(flags & BTR_KEEP_SYS_FLAG)) { + + row_upd_index_entry_sys_field(entry, index, + DATA_ROLL_PTR, roll_ptr); + } + } + + return(DB_SUCCESS); +} + +/***************************************************************** +Tries to perform an insert to a page in an index tree, next to cursor. +It is assumed that mtr holds an x-latch on the page. The operation does +not succeed if there is too little space on the page. If there is just +one record on the page, the insert will always succeed; this is to +prevent trying to split a page with just one record. */ + +ulint +btr_cur_optimistic_insert( +/*======================*/ + /* out: DB_SUCCESS, DB_WAIT_LOCK, + DB_FAIL, or error number */ + ulint flags, /* in: undo logging and locking flags: if not + zero, the parameters index and thr should be + specified */ + btr_cur_t* cursor, /* in: cursor on page after which to insert; + cursor stays valid */ + dtuple_t* entry, /* in: entry to insert */ + rec_t** rec, /* out: pointer to inserted record if + succeed */ + que_thr_t* thr, /* in: query thread or NULL */ + mtr_t* mtr) /* in: mtr */ +{ + dict_index_t* index; + page_cur_t* page_cursor; + page_t* page; + ulint max_size; + rec_t* dummy_rec; + ulint level; + ibool reorg; + ibool inherit; + ulint rec_size; + ulint data_size; + ulint extra_size; + ulint type; + ulint err; + + ut_ad(dtuple_check_typed(entry)); + + page = btr_cur_get_page(cursor); + index = cursor->index; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + max_size = page_get_max_insert_size_after_reorganize(page, 1); + level = btr_page_get_level(page, mtr); + + /* Calculate the record size when entry is converted to a record */ + data_size = dtuple_get_data_size(entry); + extra_size = rec_get_converted_extra_size(data_size, + dtuple_get_n_fields(entry)); + rec_size = data_size + extra_size; + + if (rec_size >= page_get_free_space_of_empty() / 2) { + + return(DB_TOO_BIG_RECORD); + } + + /* If there have been many consecutive inserts, and we are on the leaf + level, check if we have to split the page to reserve enough free space + for future updates of records. */ + + type = index->type; + + if ((type & DICT_CLUSTERED) + && (dict_tree_get_space_reserve(index->tree) + rec_size > max_size) + && (page_get_n_recs(page) >= 2) + && (0 == level) + && (btr_page_get_split_rec_to_right(cursor, &dummy_rec) + || btr_page_get_split_rec_to_left(cursor, &dummy_rec))) { + + return(DB_FAIL); + } + + if (!(((max_size >= rec_size) + && (max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT)) + || (page_get_max_insert_size(page, 1) >= rec_size) + || (page_get_n_recs(page) <= 1))) { + + return(DB_FAIL); + } + + /* Check locks and write to the undo log, if specified */ + err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, &inherit); + + if (err != DB_SUCCESS) { + + return(err); + } + + page_cursor = btr_cur_get_page_cur(cursor); + + reorg = FALSE; + + /* Now, try the insert */ + + *rec = page_cur_insert_rec_low(page_cursor, entry, data_size, + NULL, mtr); + if (!(*rec)) { + /* If the record did not fit, reorganize */ + btr_page_reorganize(page, mtr); + + ut_ad(page_get_max_insert_size(page, 1) == max_size); + + reorg = TRUE; + + page_cur_search(page, entry, PAGE_CUR_LE, page_cursor); + + *rec = page_cur_tuple_insert(page_cursor, entry, mtr); + + ut_a(*rec); /* <- We calculated above the record would fit */ + } + +#ifdef BTR_CUR_HASH_ADAPT + if (!reorg && (0 == level) && (cursor->flag == BTR_CUR_HASH)) { + btr_search_update_hash_node_on_insert(cursor); + } else { + btr_search_update_hash_on_insert(cursor); + } +#endif + if (!(flags & BTR_NO_LOCKING_FLAG) && inherit) { + + lock_update_insert(*rec); + } + +/* printf("Insert to page %lu, max ins size %lu, rec %lu ind type %lu\n", + buf_frame_get_page_no(page), max_size, + rec_size + PAGE_DIR_SLOT_SIZE, type); +*/ + if (!(type & (DICT_CLUSTERED | DICT_UNIQUE))) { + /* We have added a record to page: update its free bits */ + ibuf_update_free_bits_if_full(cursor->index, page, max_size, + rec_size + PAGE_DIR_SLOT_SIZE); + } + + return(DB_SUCCESS); +} + +/***************************************************************** +Performs an insert on a page of an index tree. It is assumed that mtr +holds an x-latch on the tree and on the cursor page. If the insert is +made on the leaf level, to avoid deadlocks, mtr must also own x-latches +to brothers of page, if those brothers exist. */ + +ulint +btr_cur_pessimistic_insert( +/*=======================*/ + /* out: DB_SUCCESS or error number */ + ulint flags, /* in: undo logging and locking flags: if not + zero, the parameter thr should be + specified; if no undo logging is specified, + then the caller must have reserved enough + free extents in the file space so that the + insertion will certainly succeed */ + btr_cur_t* cursor, /* in: cursor after which to insert; + cursor stays valid */ + dtuple_t* entry, /* in: entry to insert */ + rec_t** rec, /* out: pointer to inserted record if + succeed */ + que_thr_t* thr, /* in: query thread or NULL */ + mtr_t* mtr) /* in: mtr */ +{ + page_t* page; + ulint err; + ibool dummy_inh; + ibool success; + ulint n_extents = 0; + + ut_ad(dtuple_check_typed(entry)); + + page = btr_cur_get_page(cursor); + + ut_ad(mtr_memo_contains(mtr, + dict_tree_get_lock(btr_cur_get_tree(cursor)), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + + /* Try first an optimistic insert; reset the cursor flag: we do not + assume anything of how it was positioned */ + + cursor->flag = BTR_CUR_BINARY; + + err = btr_cur_optimistic_insert(flags, cursor, entry, rec, thr, mtr); + + if (err != DB_FAIL) { + + return(err); + } + + /* Retry with a pessimistic insert. Check locks and write to undo log, + if specified */ + + err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, &dummy_inh); + + if (err != DB_SUCCESS) { + + return(err); + } + + if (!(flags & BTR_NO_UNDO_LOG_FLAG)) { + /* First reserve enough free space for the file segments + of the index tree, so that the insert will not fail because + of lack of space */ + + n_extents = cursor->tree_height / 16 + 3; + + success = fsp_reserve_free_extents(cursor->index->space, + n_extents, FSP_NORMAL, mtr); + if (!success) { + err = DB_OUT_OF_FILE_SPACE; + + return(err); + } + } + + if (dict_tree_get_page(cursor->index->tree) + == buf_frame_get_page_no(page)) { + + /* The page is the root page */ + *rec = btr_root_raise_and_insert(cursor, entry, mtr); + } else { + *rec = btr_page_split_and_insert(cursor, entry, mtr); + } + + btr_cur_position(cursor->index, page_rec_get_prev(*rec), cursor); + +#ifdef BTR_CUR_ADAPT + btr_search_update_hash_on_insert(cursor); +#endif + if (!(flags & BTR_NO_LOCKING_FLAG)) { + + lock_update_insert(*rec); + } + + err = DB_SUCCESS; + + if (n_extents > 0) { + fil_space_release_free_extents(cursor->index->space, n_extents); + } + + return(err); +} + +/*==================== B-TREE UPDATE =========================*/ +/* Only clustered index records are modified using these functions */ + +/***************************************************************** +For an update, checks the locks and does the undo logging. */ +UNIV_INLINE +ulint +btr_cur_upd_lock_and_undo( +/*======================*/ + /* out: DB_SUCCESS, DB_WAIT_LOCK, or error + number */ + ulint flags, /* in: undo logging and locking flags */ + btr_cur_t* cursor, /* in: cursor on record to update */ + upd_t* update, /* in: update vector */ + ulint cmpl_info,/* in: compiler info on secondary index + updates */ + que_thr_t* thr, /* in: query thread */ + dulint* roll_ptr)/* out: roll pointer */ +{ + dict_index_t* index; + rec_t* rec; + ulint err; + + ut_ad(cursor && update && thr && roll_ptr); + + /* Only clustered index records are updated using this function */ + ut_ad((cursor->index)->type & DICT_CLUSTERED); + + rec = btr_cur_get_rec(cursor); + index = cursor->index; + + /* Check if we have to wait for a lock: enqueue an explicit lock + request if yes */ + + err = DB_SUCCESS; + + if (!(flags & BTR_NO_LOCKING_FLAG)) { + err = lock_clust_rec_modify_check_and_lock(flags, rec, index, + thr); + if (err != DB_SUCCESS) { + + return(err); + } + } + + /* Append the info about the update in the undo log */ + + err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr, + index, NULL, update, + cmpl_info, rec, roll_ptr); + return(err); +} + +/*************************************************************** +Writes a redo log record of updating a record in-place. */ +UNIV_INLINE +void +btr_cur_update_in_place_log( +/*========================*/ + ulint flags, /* in: flags */ + rec_t* rec, /* in: record */ + dict_index_t* index, /* in: index where cursor positioned */ + upd_t* update, /* in: update vector */ + trx_t* trx, /* in: transaction */ + dulint roll_ptr, /* in: roll ptr */ + mtr_t* mtr) /* in: mtr */ +{ + byte* log_ptr; + + log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN); + + log_ptr = mlog_write_initial_log_record_fast(rec, + MLOG_REC_UPDATE_IN_PLACE, log_ptr, mtr); + + mach_write_to_1(log_ptr, flags); + log_ptr++; + + log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr, + mtr); + mach_write_to_2(log_ptr, rec - buf_frame_align(rec)); + log_ptr += 2; + + row_upd_index_write_log(update, log_ptr, mtr); +} + +/*************************************************************** +Parses a redo log record of updating a record in-place. */ + +byte* +btr_cur_parse_update_in_place( +/*==========================*/ + /* out: end of log record or NULL */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + page_t* page) /* in: page or NULL */ +{ + ulint flags; + rec_t* rec; + upd_t* update; + ulint pos; + dulint trx_id; + dulint roll_ptr; + ulint rec_offset; + mem_heap_t* heap; + + if (end_ptr < ptr + 1) { + + return(NULL); + } + + flags = mach_read_from_1(ptr); + ptr++; + + ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr); + + if (ptr == NULL) { + + return(NULL); + } + + if (end_ptr < ptr + 2) { + + return(NULL); + } + + rec_offset = mach_read_from_2(ptr); + ptr += 2; + + heap = mem_heap_create(256); + + ptr = row_upd_index_parse(ptr, end_ptr, heap, &update); + + if (ptr == NULL) { + mem_heap_free(heap); + + return(NULL); + } + + if (!page) { + mem_heap_free(heap); + + return(ptr); + } + + rec = page + rec_offset; + + /* We do not need to reserve btr_search_latch, as the page is only + being recovered, and there cannot be a hash index to it. */ + + if (!(flags & BTR_KEEP_SYS_FLAG)) { + row_upd_rec_sys_fields_in_recovery(rec, pos, trx_id, roll_ptr); + } + + row_upd_rec_in_place(rec, update); + + mem_heap_free(heap); + + return(ptr); +} + +/***************************************************************** +Updates a record when the update causes no size changes in its fields. */ + +ulint +btr_cur_update_in_place( +/*====================*/ + /* out: DB_SUCCESS or error number */ + ulint flags, /* in: undo logging and locking flags */ + btr_cur_t* cursor, /* in: cursor on the record to update; + cursor stays valid and positioned on the + same record */ + upd_t* update, /* in: update vector */ + ulint cmpl_info,/* in: compiler info on secondary index + updates */ + que_thr_t* thr, /* in: query thread */ + mtr_t* mtr) /* in: mtr */ +{ + dict_index_t* index; + buf_block_t* block; + ulint err; + rec_t* rec; + dulint roll_ptr; + trx_t* trx; + + /* Only clustered index records are updated using this function */ + ut_ad((cursor->index)->type & DICT_CLUSTERED); + + rec = btr_cur_get_rec(cursor); + index = cursor->index; + trx = thr_get_trx(thr); + + /* Do lock checking and undo logging */ + err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, + thr, &roll_ptr); + if (err != DB_SUCCESS) { + + return(err); + } + + block = buf_block_align(rec); + + if (block->is_hashed) { + rw_lock_x_lock(&btr_search_latch); + } + + if (!(flags & BTR_KEEP_SYS_FLAG)) { + row_upd_rec_sys_fields(rec, index, trx, roll_ptr); + } + + /* FIXME: in a mixed tree, all records may not have enough ordering + fields for btr search: */ + + row_upd_rec_in_place(rec, update); + + if (block->is_hashed) { + rw_lock_x_unlock(&btr_search_latch); + } + + btr_cur_update_in_place_log(flags, rec, index, update, trx, roll_ptr, + mtr); + return(DB_SUCCESS); +} + +/***************************************************************** +Tries to update a record on a page in an index tree. It is assumed that mtr +holds an x-latch on the page. The operation does not succeed if there is too +little space on the page or if the update would result in too empty a page, +so that tree compression is recommended. */ + +ulint +btr_cur_optimistic_update( +/*======================*/ + /* out: DB_SUCCESS, or DB_OVERFLOW if the + updated record does not fit, DB_UNDERFLOW + if the page would become too empty */ + ulint flags, /* in: undo logging and locking flags */ + btr_cur_t* cursor, /* in: cursor on the record to update; + cursor stays valid and positioned on the + same record */ + upd_t* update, /* in: update vector; this must also + contain trx id and roll ptr fields */ + ulint cmpl_info,/* in: compiler info on secondary index + updates */ + que_thr_t* thr, /* in: query thread */ + mtr_t* mtr) /* in: mtr */ +{ + dict_index_t* index; + page_cur_t* page_cursor; + ulint err; + page_t* page; + rec_t* rec; + ulint max_size; + ulint new_rec_size; + ulint old_rec_size; + dtuple_t* new_entry; + dulint roll_ptr; + trx_t* trx; + mem_heap_t* heap; + ibool reorganized = FALSE; + + /* Only clustered index records are updated using this function */ + ut_ad((cursor->index)->type & DICT_CLUSTERED); + + page = btr_cur_get_page(cursor); + rec = btr_cur_get_rec(cursor); + index = cursor->index; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + if (!row_upd_changes_field_size(rec, index, update)) { + + /* The simplest and most common case: the update does not + change the size of any field */ + + return(btr_cur_update_in_place(flags, cursor, update, + cmpl_info, thr, mtr)); + } + + page_cursor = btr_cur_get_page_cur(cursor); + + heap = mem_heap_create(1024); + + new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); + + row_upd_clust_index_replace_new_col_vals(new_entry, update); + + old_rec_size = rec_get_size(rec); + new_rec_size = rec_get_converted_size(new_entry); + + if (new_rec_size >= page_get_free_space_of_empty() / 2) { + + mem_heap_free(heap); + + return(DB_TOO_BIG_RECORD); + } + + max_size = old_rec_size + + page_get_max_insert_size_after_reorganize(page, 1); + + if (page_get_data_size(page) - old_rec_size + new_rec_size + < BTR_CUR_PAGE_COMPRESS_LIMIT) { + + /* The page would become too empty */ + + mem_heap_free(heap); + + return(DB_UNDERFLOW); + } + + if (!(((max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT) + && (max_size >= new_rec_size)) + || (page_get_n_recs(page) <= 1))) { + + /* There was not enough space, or it did not pay to + reorganize: for simplicity, we decide what to do assuming a + reorganization is needed, though it might not be necessary */ + + mem_heap_free(heap); + + return(DB_OVERFLOW); + } + + /* Do lock checking and undo logging */ + err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, thr, + &roll_ptr); + if (err != DB_SUCCESS) { + + mem_heap_free(heap); + + return(err); + } + + /* Ok, we may do the replacement. Store on the page infimum the + explicit locks on rec, before deleting rec (see the comment in + .._pessimistic_update). */ + + lock_rec_store_on_page_infimum(rec); + + btr_search_update_hash_on_delete(cursor); + + page_cur_delete_rec(page_cursor, mtr); + + page_cur_move_to_prev(page_cursor); + + trx = thr_get_trx(thr); + + if (!(flags & BTR_KEEP_SYS_FLAG)) { + row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, + roll_ptr); + row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID, + trx->id); + } + + rec = btr_cur_insert_if_possible(cursor, new_entry, &reorganized, mtr); + + ut_a(rec); /* <- We calculated above the insert would fit */ + + /* Restore the old explicit lock state on the record */ + + lock_rec_restore_from_page_infimum(rec, page); + + page_cur_move_to_next(page_cursor); + + mem_heap_free(heap); + + return(DB_SUCCESS); +} + +/***************************************************************** +If, in a split, a new supremum record was created as the predecessor of the +updated record, the supremum record must inherit exactly the locks on the +updated record. In the split it may have inherited locks from the successor +of the updated record, which is not correct. This function restores the +right locks for the new supremum. */ +static +void +btr_cur_pess_upd_restore_supremum( +/*==============================*/ + rec_t* rec, /* in: updated record */ + mtr_t* mtr) /* in: mtr */ +{ + page_t* page; + page_t* prev_page; + ulint space; + ulint prev_page_no; + + page = buf_frame_align(rec); + + if (page_rec_get_next(page_get_infimum_rec(page)) != rec) { + /* Updated record is not the first user record on its page */ + + return; + } + + space = buf_frame_get_space_id(page); + prev_page_no = btr_page_get_prev(page, mtr); + + ut_ad(prev_page_no != FIL_NULL); + prev_page = buf_page_get_with_no_latch(space, prev_page_no, mtr); + + /* We must already have an x-latch to prev_page! */ + ut_ad(mtr_memo_contains(mtr, buf_block_align(prev_page), + MTR_MEMO_PAGE_X_FIX)); + + lock_rec_reset_and_inherit_gap_locks(page_get_supremum_rec(prev_page), + rec); +} + +/***************************************************************** +Performs an update of a record on a page of a tree. It is assumed +that mtr holds an x-latch on the tree and on the cursor page. If the +update is made on the leaf level, to avoid deadlocks, mtr must also +own x-latches to brothers of page, if those brothers exist. */ + +ulint +btr_cur_pessimistic_update( +/*=======================*/ + /* out: DB_SUCCESS or error code */ + ulint flags, /* in: undo logging, locking, and rollback + flags */ + btr_cur_t* cursor, /* in: cursor on the record to update; + cursor does not stay valid */ + upd_t* update, /* in: update vector; this is allowed also + contain trx id and roll ptr fields, but + the values in update vector have no effect */ + ulint cmpl_info,/* in: compiler info on secondary index + updates */ + que_thr_t* thr, /* in: query thread */ + mtr_t* mtr) /* in: mtr */ +{ + dict_index_t* index; + page_t* page; + dict_tree_t* tree; + rec_t* rec; + page_cur_t* page_cursor; + dtuple_t* new_entry; + mem_heap_t* heap; + ulint err; + ulint optim_err; + ibool dummy_reorganized; + dulint roll_ptr; + trx_t* trx; + ibool was_first; + ibool success; + ulint n_extents = 0; + + page = btr_cur_get_page(cursor); + rec = btr_cur_get_rec(cursor); + index = cursor->index; + tree = index->tree; + + ut_ad(index->type & DICT_CLUSTERED); + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + + optim_err = btr_cur_optimistic_update(flags, cursor, update, + cmpl_info, thr, mtr); + + if (optim_err != DB_UNDERFLOW && optim_err != DB_OVERFLOW) { + + return(optim_err); + } + + /* Do lock checking and undo logging */ + err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, + thr, &roll_ptr); + if (err != DB_SUCCESS) { + + return(err); + } + + if (optim_err == DB_OVERFLOW) { + /* First reserve enough free space for the file segments + of the index tree, so that the update will not fail because + of lack of space */ + + n_extents = cursor->tree_height / 16 + 3; + + success = fsp_reserve_free_extents(cursor->index->space, + n_extents, FSP_NORMAL, mtr); + if (!success) { + err = DB_OUT_OF_FILE_SPACE; + + return(err); + } + } + + heap = mem_heap_create(1024); + + trx = thr_get_trx(thr); + + new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); + + row_upd_clust_index_replace_new_col_vals(new_entry, update); + + if (!(flags & BTR_KEEP_SYS_FLAG)) { + row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, + roll_ptr); + row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID, + trx->id); + } + + page_cursor = btr_cur_get_page_cur(cursor); + + /* Store state of explicit locks on rec on the page infimum record, + before deleting rec. The page infimum acts as a dummy carrier of the + locks, taking care also of lock releases, before we can move the locks + back on the actual record. There is a special case: if we are + inserting on the root page and the insert causes a call of + btr_root_raise_and_insert. Therefore we cannot in the lock system + delete the lock structs set on the root page even if the root + page carries just node pointers. */ + + lock_rec_store_on_page_infimum(rec); + + btr_search_update_hash_on_delete(cursor); + page_cur_delete_rec(page_cursor, mtr); + + page_cur_move_to_prev(page_cursor); + + if (optim_err == DB_UNDERFLOW) { + rec = btr_cur_insert_if_possible(cursor, new_entry, + &dummy_reorganized, mtr); + ut_a(rec); /* <- We knew the insert would fit */ + + lock_rec_restore_from_page_infimum(rec, page); + + btr_cur_compress_if_useful(cursor, mtr); + + err = DB_SUCCESS; + mem_heap_free(heap); + + goto return_after_reservations; + } + + if (page_cur_is_before_first(page_cursor)) { + /* The record to be updated was positioned as the first user + record on its page */ + + was_first = TRUE; + } else { + was_first = FALSE; + } + + /* The first parameter means that no lock checking and undo logging + is made in the insert */ + + err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG + | BTR_NO_LOCKING_FLAG + | BTR_KEEP_SYS_FLAG, + cursor, new_entry, &rec, NULL, mtr); + ut_a(rec); + ut_a(err == DB_SUCCESS); + + lock_rec_restore_from_page_infimum(rec, page); + + /* If necessary, restore also the correct lock state for a new, + preceding supremum record created in a page split. While the old + record was nonexistent, the supremum might have inherited its locks + from a wrong record. */ + + if (!was_first) { + btr_cur_pess_upd_restore_supremum(rec, mtr); + } + + mem_heap_free(heap); + +return_after_reservations: + + if (n_extents > 0) { + fil_space_release_free_extents(cursor->index->space, n_extents); + } + + return(err); +} + +/*==================== B-TREE DELETE MARK AND UNMARK ===============*/ + +/******************************************************************** +Writes the redo log record for delete marking or unmarking of an index +record. */ +UNIV_INLINE +void +btr_cur_del_mark_set_clust_rec_log( +/*===============================*/ + ulint flags, /* in: flags */ + rec_t* rec, /* in: record */ + dict_index_t* index, /* in: index of the record */ + ibool val, /* in: value to set */ + trx_t* trx, /* in: deleting transaction */ + dulint roll_ptr,/* in: roll ptr to the undo log record */ + mtr_t* mtr) /* in: mtr */ +{ + byte* log_ptr; + + log_ptr = mlog_open(mtr, 30); + + log_ptr = mlog_write_initial_log_record_fast(rec, + MLOG_REC_CLUST_DELETE_MARK, log_ptr, mtr); + + mach_write_to_1(log_ptr, flags); + log_ptr++; + mach_write_to_1(log_ptr, val); + log_ptr++; + + log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr, + mtr); + mach_write_to_2(log_ptr, rec - buf_frame_align(rec)); + log_ptr += 2; + + mlog_close(mtr, log_ptr); +} + +/******************************************************************** +Parses the redo log record for delete marking or unmarking of a clustered +index record. */ + +byte* +btr_cur_parse_del_mark_set_clust_rec( +/*=================================*/ + /* out: end of log record or NULL */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + page_t* page) /* in: page or NULL */ +{ + ulint flags; + ibool val; + ulint pos; + dulint trx_id; + dulint roll_ptr; + ulint offset; + rec_t* rec; + + if (end_ptr < ptr + 2) { + + return(NULL); + } + + flags = mach_read_from_1(ptr); + ptr++; + val = mach_read_from_1(ptr); + ptr++; + + ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr); + + if (ptr == NULL) { + + return(NULL); + } + + if (end_ptr < ptr + 2) { + + return(NULL); + } + + offset = mach_read_from_2(ptr); + ptr += 2; + + if (page) { + rec = page + offset; + + if (!(flags & BTR_KEEP_SYS_FLAG)) { + row_upd_rec_sys_fields_in_recovery(rec, pos, trx_id, + roll_ptr); + } + + /* We do not need to reserve btr_search_latch, as the page + is only being recovered, and there cannot be a hash index to + it. */ + + rec_set_deleted_flag(rec, val); + } + + return(ptr); +} + +/*************************************************************** +Marks a clustered index record deleted. Writes an undo log record to +undo log on this delete marking. Writes in the trx id field the id +of the deleting transaction, and in the roll ptr field pointer to the +undo log record created. */ + +ulint +btr_cur_del_mark_set_clust_rec( +/*===========================*/ + /* out: DB_SUCCESS, DB_LOCK_WAIT, or error + number */ + ulint flags, /* in: undo logging and locking flags */ + btr_cur_t* cursor, /* in: cursor */ + ibool val, /* in: value to set */ + que_thr_t* thr, /* in: query thread */ + mtr_t* mtr) /* in: mtr */ +{ + dict_index_t* index; + buf_block_t* block; + dulint roll_ptr; + ulint err; + rec_t* rec; + trx_t* trx; + + rec = btr_cur_get_rec(cursor); + index = cursor->index; + + ut_ad(index->type & DICT_CLUSTERED); + ut_ad(rec_get_deleted_flag(rec) == FALSE); + + err = lock_clust_rec_modify_check_and_lock(flags, rec, index, thr); + + if (err != DB_SUCCESS) { + + return(err); + } + + err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr, + index, NULL, NULL, 0, rec, + &roll_ptr); + if (err != DB_SUCCESS) { + + return(err); + } + + block = buf_block_align(rec); + + if (block->is_hashed) { + rw_lock_x_lock(&btr_search_latch); + } + + rec_set_deleted_flag(rec, val); + + trx = thr_get_trx(thr); + + if (!(flags & BTR_KEEP_SYS_FLAG)) { + + row_upd_rec_sys_fields(rec, index, trx, roll_ptr); + } + + if (block->is_hashed) { + rw_lock_x_unlock(&btr_search_latch); + } + + btr_cur_del_mark_set_clust_rec_log(flags, rec, index, val, trx, + roll_ptr, mtr); + return(DB_SUCCESS); +} + +/******************************************************************** +Writes the redo log record for a delete mark setting of a secondary +index record. */ +UNIV_INLINE +void +btr_cur_del_mark_set_sec_rec_log( +/*=============================*/ + rec_t* rec, /* in: record */ + ibool val, /* in: value to set */ + mtr_t* mtr) /* in: mtr */ +{ + byte* log_ptr; + + log_ptr = mlog_open(mtr, 30); + + log_ptr = mlog_write_initial_log_record_fast(rec, + MLOG_REC_SEC_DELETE_MARK, log_ptr, mtr); + + mach_write_to_1(log_ptr, val); + log_ptr++; + + mach_write_to_2(log_ptr, rec - buf_frame_align(rec)); + log_ptr += 2; + + mlog_close(mtr, log_ptr); +} + +/******************************************************************** +Parses the redo log record for delete marking or unmarking of a secondary +index record. */ + +byte* +btr_cur_parse_del_mark_set_sec_rec( +/*===============================*/ + /* out: end of log record or NULL */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + page_t* page) /* in: page or NULL */ +{ + ibool val; + ulint offset; + rec_t* rec; + + if (end_ptr < ptr + 3) { + + return(NULL); + } + + val = mach_read_from_1(ptr); + ptr++; + + offset = mach_read_from_2(ptr); + ptr += 2; + + if (page) { + rec = page + offset; + + /* We do not need to reserve btr_search_latch, as the page + is only being recovered, and there cannot be a hash index to + it. */ + + rec_set_deleted_flag(rec, val); + } + + return(ptr); +} + +/*************************************************************** +Sets a secondary index record delete mark to TRUE or FALSE. */ + +ulint +btr_cur_del_mark_set_sec_rec( +/*=========================*/ + /* out: DB_SUCCESS, DB_LOCK_WAIT, or error + number */ + ulint flags, /* in: locking flag */ + btr_cur_t* cursor, /* in: cursor */ + ibool val, /* in: value to set */ + que_thr_t* thr, /* in: query thread */ + mtr_t* mtr) /* in: mtr */ +{ + buf_block_t* block; + rec_t* rec; + ulint err; + + rec = btr_cur_get_rec(cursor); + + err = lock_sec_rec_modify_check_and_lock(flags, rec, cursor->index, + thr); + if (err != DB_SUCCESS) { + + return(err); + } + + block = buf_block_align(rec); + + if (block->is_hashed) { + rw_lock_x_lock(&btr_search_latch); + } + + rec_set_deleted_flag(rec, val); + + if (block->is_hashed) { + rw_lock_x_unlock(&btr_search_latch); + } + + btr_cur_del_mark_set_sec_rec_log(rec, val, mtr); + + return(DB_SUCCESS); +} + +/*************************************************************** +Sets a secondary index record delete mark to FALSE. This function is only +used by the insert buffer insert merge mechanism. */ + +void +btr_cur_del_unmark_for_ibuf( +/*========================*/ + rec_t* rec, /* in: record to delete unmark */ + mtr_t* mtr) /* in: mtr */ +{ + /* We do not need to reserve btr_search_latch, as the page has just + been read to the buffer pool and there cannot be a hash index to it. */ + + rec_set_deleted_flag(rec, FALSE); + + btr_cur_del_mark_set_sec_rec_log(rec, FALSE, mtr); +} + +/*==================== B-TREE RECORD REMOVE =========================*/ + +/***************************************************************** +Tries to compress a page of the tree on the leaf level. It is assumed +that mtr holds an x-latch on the tree and on the cursor page. To avoid +deadlocks, mtr must also own x-latches to brothers of page, if those +brothers exist. NOTE: it is assumed that the caller has reserved enough +free extents so that the compression will always succeed if done! */ + +void +btr_cur_compress( +/*=============*/ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid */ + mtr_t* mtr) /* in: mtr */ +{ + ut_ad(mtr_memo_contains(mtr, + dict_tree_get_lock(btr_cur_get_tree(cursor)), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align( + btr_cur_get_page(cursor)), + MTR_MEMO_PAGE_X_FIX)); + ut_ad(btr_page_get_level(btr_cur_get_page(cursor), mtr) == 0); + + btr_compress(cursor, mtr); +} + +/***************************************************************** +Tries to compress a page of the tree if it seems useful. It is assumed +that mtr holds an x-latch on the tree and on the cursor page. To avoid +deadlocks, mtr must also own x-latches to brothers of page, if those +brothers exist. NOTE: it is assumed that the caller has reserved enough +free extents so that the compression will always succeed if done! */ + +ibool +btr_cur_compress_if_useful( +/*=======================*/ + /* out: TRUE if compression occurred */ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid if compression + occurs */ + mtr_t* mtr) /* in: mtr */ +{ + ut_ad(mtr_memo_contains(mtr, + dict_tree_get_lock(btr_cur_get_tree(cursor)), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align( + btr_cur_get_page(cursor)), + MTR_MEMO_PAGE_X_FIX)); + + if (btr_cur_compress_recommendation(cursor, mtr)) { + + btr_compress(cursor, mtr); + + return(TRUE); + } + + return(FALSE); +} + +/*********************************************************** +Removes the record on which the tree cursor is positioned on a leaf page. +It is assumed that the mtr has an x-latch on the page where the cursor is +positioned, but no latch on the whole tree. */ + +ibool +btr_cur_optimistic_delete( +/*======================*/ + /* out: TRUE if success, i.e., the page + did not become too empty */ + btr_cur_t* cursor, /* in: cursor on leaf page, on the record to + delete; cursor stays valid: if deletion + succeeds, on function exit it points to the + successor of the deleted record */ + mtr_t* mtr) /* in: mtr */ +{ + page_t* page; + ulint max_ins_size; + + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_page(cursor)), + MTR_MEMO_PAGE_X_FIX)); + /* This is intended only for leaf page deletions */ + + page = btr_cur_get_page(cursor); + + ut_ad(btr_page_get_level(page, mtr) == 0); + + if (btr_cur_can_delete_without_compress(cursor, mtr)) { + + lock_update_delete(btr_cur_get_rec(cursor)); + + btr_search_update_hash_on_delete(cursor); + + max_ins_size = page_get_max_insert_size_after_reorganize(page, + 1); + page_cur_delete_rec(btr_cur_get_page_cur(cursor), mtr); + + ibuf_update_free_bits_low(cursor->index, page, max_ins_size, + mtr); + return(TRUE); + } + + return(FALSE); +} + +/***************************************************************** +Removes the record on which the tree cursor is positioned. Tries +to compress the page if its fillfactor drops below a threshold +or if it is the only page on the level. It is assumed that mtr holds +an x-latch on the tree and on the cursor page. To avoid deadlocks, +mtr must also own x-latches to brothers of page, if those brothers +exist. */ + +ibool +btr_cur_pessimistic_delete( +/*=======================*/ + /* out: TRUE if compression occurred */ + ulint* err, /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE; + the latter may occur because we may have + to update node pointers on upper levels, + and in the case of variable length keys + these may actually grow in size */ + ibool has_reserved_extents, /* in: TRUE if the + caller has already reserved enough free + extents so that he knows that the operation + will succeed */ + btr_cur_t* cursor, /* in: cursor on the record to delete; + if compression does not occur, the cursor + stays valid: it points to successor of + deleted record on function exit */ + mtr_t* mtr) /* in: mtr */ +{ + page_t* page; + dict_tree_t* tree; + rec_t* rec; + dtuple_t* node_ptr; + ulint n_extents = 0; + ibool success; + ibool ret = FALSE; + mem_heap_t* heap; + + page = btr_cur_get_page(cursor); + tree = btr_cur_get_tree(cursor); + + ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + if (!has_reserved_extents) { + /* First reserve enough free space for the file segments + of the index tree, so that the node pointer updates will + not fail because of lack of space */ + + n_extents = cursor->tree_height / 32 + 1; + + success = fsp_reserve_free_extents(cursor->index->space, + n_extents, FSP_CLEANING, mtr); + if (!success) { + *err = DB_OUT_OF_FILE_SPACE; + + return(FALSE); + } + } + + if ((page_get_n_recs(page) < 2) + && (dict_tree_get_page(btr_cur_get_tree(cursor)) + != buf_frame_get_page_no(page))) { + + /* If there is only one record, drop the whole page in + btr_discard_page, if this is not the root page */ + + btr_discard_page(cursor, mtr); + + *err = DB_SUCCESS; + ret = TRUE; + + goto return_after_reservations; + } + + rec = btr_cur_get_rec(cursor); + + lock_update_delete(rec); + + if ((btr_page_get_level(page, mtr) > 0) + && (page_rec_get_next(page_get_infimum_rec(page)) == rec)) { + + if (btr_page_get_prev(page, mtr) == FIL_NULL) { + + /* If we delete the leftmost node pointer on a + non-leaf level, we must mark the new leftmost node + pointer as the predefined minimum record */ + + btr_set_min_rec_mark(page_rec_get_next(rec), mtr); + } else { + /* Otherwise, if we delete the leftmost node pointer + on a page, we have to change the father node pointer + so that it is equal to the new leftmost node pointer + on the page */ + + btr_node_ptr_delete(tree, page, mtr); + + heap = mem_heap_create(256); + + node_ptr = dict_tree_build_node_ptr( + tree, page_rec_get_next(rec), + buf_frame_get_page_no(page), + heap); + + btr_insert_on_non_leaf_level(tree, + btr_page_get_level(page, mtr) + 1, + node_ptr, mtr); + + mem_heap_free(heap); + } + } + + btr_search_update_hash_on_delete(cursor); + + page_cur_delete_rec(btr_cur_get_page_cur(cursor), mtr); + + ut_ad(btr_check_node_ptr(tree, page, mtr)); + + *err = DB_SUCCESS; + +return_after_reservations: + + if (ret == FALSE) { + ret = btr_cur_compress_if_useful(cursor, mtr); + } + + if (n_extents > 0) { + fil_space_release_free_extents(cursor->index->space, n_extents); + } + + return(ret); +} + +/*********************************************************************** +Adds path information to the cursor for the current page, for which +the binary search has been performed. */ +static +void +btr_cur_add_path_info( +/*==================*/ + btr_cur_t* cursor, /* in: cursor positioned on a page */ + ulint height, /* in: height of the page in tree; + 0 means leaf node */ + ulint root_height) /* in: root node height in tree */ +{ + btr_path_t* slot; + rec_t* rec; + + ut_a(cursor->path_arr); + + if (root_height >= BTR_PATH_ARRAY_N_SLOTS - 1) { + /* Do nothing; return empty path */ + + slot = cursor->path_arr; + slot->nth_rec = ULINT_UNDEFINED; + + return; + } + + if (height == 0) { + /* Mark end of slots for path */ + slot = cursor->path_arr + root_height + 1; + slot->nth_rec = ULINT_UNDEFINED; + } + + rec = btr_cur_get_rec(cursor); + + slot = cursor->path_arr + (root_height - height); + + slot->nth_rec = page_rec_get_n_recs_before(rec); + slot->n_recs = page_get_n_recs(buf_frame_align(rec)); +} + +/*********************************************************************** +Estimates the number of rows in a given index range. */ + +ulint +btr_estimate_n_rows_in_range( +/*=========================*/ + /* out: estimated number of rows */ + dict_index_t* index, /* in: index */ + dtuple_t* tuple1, /* in: range start, may also be empty tuple */ + ulint mode1, /* in: search mode for range start */ + dtuple_t* tuple2, /* in: range end, may also be empty tuple */ + ulint mode2) /* in: search mode for range end */ +{ + btr_path_t path1[BTR_PATH_ARRAY_N_SLOTS]; + btr_path_t path2[BTR_PATH_ARRAY_N_SLOTS]; + btr_cur_t cursor; + btr_path_t* slot1; + btr_path_t* slot2; + ibool diverged; + ulint n_rows; + ulint i; + mtr_t mtr; + + mtr_start(&mtr); + + cursor.path_arr = path1; + + if (dtuple_get_n_fields(tuple1) > 0) { + + btr_cur_search_to_nth_level(index, 0, tuple1, mode1, + BTR_SEARCH_LEAF | BTR_ESTIMATE, + &cursor, 0, &mtr); + } else { + btr_cur_open_at_index_side(TRUE, index, + BTR_SEARCH_LEAF | BTR_ESTIMATE, + &cursor, &mtr); + } + + mtr_commit(&mtr); + + mtr_start(&mtr); + + cursor.path_arr = path2; + + if (dtuple_get_n_fields(tuple2) > 0) { + + btr_cur_search_to_nth_level(index, 0, tuple2, mode2, + BTR_SEARCH_LEAF | BTR_ESTIMATE, + &cursor, 0, &mtr); + } else { + btr_cur_open_at_index_side(FALSE, index, + BTR_SEARCH_LEAF | BTR_ESTIMATE, + &cursor, &mtr); + } + + mtr_commit(&mtr); + + /* We have the path information for the range in path1 and path2 */ + + n_rows = 1; + diverged = FALSE; + + for (i = 0; ; i++) { + ut_ad(i < BTR_PATH_ARRAY_N_SLOTS); + + slot1 = path1 + i; + slot2 = path2 + i; + + if (slot1->nth_rec == ULINT_UNDEFINED + || slot2->nth_rec == ULINT_UNDEFINED) { + + return(n_rows); + } + + if (!diverged && slot1->nth_rec != slot2->nth_rec) { + + if (slot1->nth_rec < slot2->nth_rec) { + n_rows = slot2->nth_rec - slot1->nth_rec; + } else { + /* Maybe the tree has changed between + searches */ + + return(10); + } + + diverged = TRUE; + } else if (diverged) { + n_rows = (n_rows * (slot1->n_recs + slot2->n_recs)) + / 2; + } + } +} + +/*********************************************************************** +Estimates the number of different key values in a given index. */ + +ulint +btr_estimate_number_of_different_key_vals( +/*======================================*/ + /* out: estimated number of key values */ + dict_index_t* index) /* in: index */ +{ + btr_cur_t cursor; + page_t* page; + rec_t* rec; + ulint total_n_recs = 0; + ulint n_diff_in_page; + ulint n_diff = 0; + ulint matched_fields; + ulint matched_bytes; + ulint i; + mtr_t mtr; + + if (index->type & DICT_UNIQUE) { + return(index->table->stat_n_rows); + } + + /* We sample some pages in the index to get an estimate */ + + for (i = 0; i < BTR_KEY_VAL_ESTIMATE_N_PAGES; i++) { + mtr_start(&mtr); + + btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr); + + /* Count the number of different key values minus one on this + index page: we subtract one because otherwise our algorithm + would give a wrong estimate for an index where there is + just one key value */ + + page = btr_cur_get_page(&cursor); + + rec = page_get_infimum_rec(page); + rec = page_rec_get_next(rec); + + n_diff_in_page = 0; + + while (rec != page_get_supremum_rec(page) + && page_rec_get_next(rec) + != page_get_supremum_rec(page)) { + matched_fields = 0; + matched_bytes = 0; + + cmp_rec_rec_with_match(rec, page_rec_get_next(rec), + index, &matched_fields, + &matched_bytes); + if (matched_fields < + dict_index_get_n_ordering_defined_by_user( + index)) { + n_diff_in_page++; + } + + rec = page_rec_get_next(rec); + } + + n_diff += n_diff_in_page; + + total_n_recs += page_get_n_recs(page); + + mtr_commit(&mtr); + } + + if (n_diff == 0) { + /* We play safe and assume that there are just two different + key values in the index */ + + return(2); + } + + return(index->table->stat_n_rows / (total_n_recs / n_diff)); +} diff --git a/innobase/btr/btr0pcur.c b/innobase/btr/btr0pcur.c new file mode 100644 index 00000000000..0388785b3fe --- /dev/null +++ b/innobase/btr/btr0pcur.c @@ -0,0 +1,474 @@ +/****************************************************** +The index tree persistent cursor + +(c) 1996 Innobase Oy + +Created 2/23/1996 Heikki Tuuri +*******************************************************/ + +#include "btr0pcur.h" + +#ifdef UNIV_NONINL +#include "btr0pcur.ic" +#endif + +#include "ut0byte.h" +#include "rem0cmp.h" + +/****************************************************************** +Allocates memory for a persistent cursor object and initializes the cursor. */ + +btr_pcur_t* +btr_pcur_create_for_mysql(void) +/*============================*/ + /* out, own: persistent cursor */ +{ + btr_pcur_t* pcur; + + pcur = mem_alloc(sizeof(btr_pcur_t)); + + pcur->btr_cur.index = NULL; + btr_pcur_init(pcur); + + return(pcur); +} + +/****************************************************************** +Frees the memory for a persistent cursor object. */ + +void +btr_pcur_free_for_mysql( +/*====================*/ + btr_pcur_t* cursor) /* in, own: persistent cursor */ +{ + if (cursor->old_rec_buf != NULL) { + + mem_free(cursor->old_rec_buf); + + cursor->old_rec = NULL; + cursor->old_rec_buf = NULL; + } + + cursor->btr_cur.page_cur.rec = NULL; + cursor->old_rec = NULL; + cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; + + cursor->latch_mode = BTR_NO_LATCHES; + cursor->pos_state = BTR_PCUR_NOT_POSITIONED; + + mem_free(cursor); +} + +/****************************************************************** +The position of the cursor is stored by taking an initial segment of the +record the cursor is positioned on, before, or after, and copying it to the +cursor data structure. NOTE that the page where the cursor is positioned +must not be empty! */ + +void +btr_pcur_store_position( +/*====================*/ + btr_pcur_t* cursor, /* in: persistent cursor */ + mtr_t* mtr) /* in: mtr */ +{ + page_cur_t* page_cursor; + rec_t* rec; + dict_tree_t* tree; + page_t* page; + + ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + + tree = btr_cur_get_tree(btr_pcur_get_btr_cur(cursor)); + + page_cursor = btr_pcur_get_page_cur(cursor); + + rec = page_cur_get_rec(page_cursor); + page = buf_frame_align(rec); + + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_S_FIX) + || mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + ut_a(cursor->latch_mode != BTR_NO_LATCHES); + + if (page_get_n_recs(page) == 0) { + + /* Cannot store position! */ + btr_pcur_close(cursor); + + return; + } + + if (rec == page_get_supremum_rec(page)) { + + rec = page_rec_get_prev(rec); + + cursor->rel_pos = BTR_PCUR_AFTER; + + } else if (rec == page_get_infimum_rec(page)) { + + rec = page_rec_get_next(rec); + + cursor->rel_pos = BTR_PCUR_BEFORE; + } else { + cursor->rel_pos = BTR_PCUR_ON; + } + + cursor->old_stored = BTR_PCUR_OLD_STORED; + cursor->old_rec = dict_tree_copy_rec_order_prefix(tree, rec, + &(cursor->old_rec_buf), + &(cursor->buf_size)); + + cursor->modify_clock = buf_frame_get_modify_clock(page); +} + +/****************************************************************** +Copies the stored position of a pcur to another pcur. */ + +void +btr_pcur_copy_stored_position( +/*==========================*/ + btr_pcur_t* pcur_receive, /* in: pcur which will receive the + position info */ + btr_pcur_t* pcur_donate) /* in: pcur from which the info is + copied */ +{ + if (pcur_receive->old_rec_buf) { + mem_free(pcur_receive->old_rec_buf); + } + + ut_memcpy((byte*)pcur_receive, (byte*)pcur_donate, sizeof(btr_pcur_t)); + + pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size); + + ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf, + pcur_donate->buf_size); + pcur_receive->old_rec = pcur_receive->old_rec_buf + + (pcur_donate->old_rec - pcur_donate->old_rec_buf); + +} + +/****************************************************************** +Restores the stored position of a persistent cursor bufferfixing the page and +obtaining the specified latches. If the cursor position was saved when the +(1) cursor was positioned on a user record: this function restores the position +to the last record LESS OR EQUAL to the stored record; +(2) cursor was positioned on a page infimum record: restores the position to +the last record LESS than the user record which was the successor of the page +infimum; +(3) cursor was positioned on the page supremum: restores to the first record +GREATER than the user record which was the predecessor of the supremum. */ + +ibool +btr_pcur_restore_position( +/*======================*/ + /* out: TRUE if the cursor position + was stored when it was on a user record + and it can be restored on a user record + whose ordering fields are identical to + the ones of the original user record */ + ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */ + btr_pcur_t* cursor, /* in: detached persistent cursor */ + mtr_t* mtr) /* in: mtr */ +{ + dict_tree_t* tree; + page_t* page; + dtuple_t* tuple; + ulint mode; + ulint old_mode; + mem_heap_t* heap; + + ut_a((cursor->pos_state == BTR_PCUR_WAS_POSITIONED) + || (cursor->pos_state == BTR_PCUR_IS_POSITIONED)); + ut_a(cursor->old_stored == BTR_PCUR_OLD_STORED); + ut_a(cursor->old_rec); + + page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor)); + + if ((latch_mode == BTR_SEARCH_LEAF) + || (latch_mode == BTR_MODIFY_LEAF)) { + /* Try optimistic restoration */ + + if (buf_page_optimistic_get(latch_mode, page, + cursor->modify_clock, mtr)) { + cursor->pos_state = BTR_PCUR_IS_POSITIONED; + + buf_page_dbg_add_level(page, SYNC_TREE_NODE); + + if (cursor->rel_pos == BTR_PCUR_ON) { + + cursor->latch_mode = latch_mode; + + ut_ad(cmp_rec_rec(cursor->old_rec, + btr_pcur_get_rec(cursor), + dict_tree_find_index( + btr_cur_get_tree( + btr_pcur_get_btr_cur(cursor)), + btr_pcur_get_rec(cursor))) + == 0); + + return(TRUE); + } + + return(FALSE); + } + } + + /* If optimistic restoration did not succeed, open the cursor anew */ + + heap = mem_heap_create(256); + + tree = btr_cur_get_tree(btr_pcur_get_btr_cur(cursor)); + tuple = dict_tree_build_data_tuple(tree, cursor->old_rec, heap); + + /* Save the old search mode of the cursor */ + old_mode = cursor->search_mode; + + if (cursor->rel_pos == BTR_PCUR_ON) { + mode = PAGE_CUR_LE; + } else if (cursor->rel_pos == BTR_PCUR_AFTER) { + mode = PAGE_CUR_G; + } else { + ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE); + mode = PAGE_CUR_L; + } + + btr_pcur_open_with_no_init(btr_pcur_get_btr_cur(cursor)->index, tuple, + mode, latch_mode, cursor, 0, mtr); + + cursor->old_stored = BTR_PCUR_OLD_STORED; + + /* Restore the old search mode */ + cursor->search_mode = old_mode; + + if ((cursor->rel_pos == BTR_PCUR_ON) + && btr_pcur_is_on_user_rec(cursor, mtr) + && (0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor)))) { + + mem_heap_free(heap); + + return(TRUE); + } + + mem_heap_free(heap); + + return(FALSE); +} + +/****************************************************************** +If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY, +releases the page latch and bufferfix reserved by the cursor. +NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes +made by the current mini-transaction to the data protected by the +cursor latch, as then the latch must not be released until mtr_commit. */ + +void +btr_pcur_release_leaf( +/*==================*/ + btr_pcur_t* cursor, /* in: persistent cursor */ + mtr_t* mtr) /* in: mtr */ +{ + page_t* page; + + ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + + page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor)); + + btr_leaf_page_release(page, cursor->latch_mode, mtr); + + cursor->latch_mode = BTR_NO_LATCHES; + + cursor->pos_state = BTR_PCUR_WAS_POSITIONED; +} + +/************************************************************* +Moves the persistent cursor to the first record on the next page. Releases the +latch on the current page, and bufferunfixes it. Note that there must not be +modifications on the current page, as then the x-latch can be released only in +mtr_commit. */ + +void +btr_pcur_move_to_next_page( +/*=======================*/ + btr_pcur_t* cursor, /* in: persistent cursor; must be on the + last record of the current page */ + mtr_t* mtr) /* in: mtr */ +{ + ulint next_page_no; + ulint space; + page_t* page; + page_t* next_page; + + ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + ut_ad(btr_pcur_is_after_last_on_page(cursor, mtr)); + + cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; + + page = btr_pcur_get_page(cursor); + + next_page_no = btr_page_get_next(page, mtr); + space = buf_frame_get_space_id(page); + + ut_ad(next_page_no != FIL_NULL); + + next_page = btr_page_get(space, next_page_no, cursor->latch_mode, mtr); + + btr_leaf_page_release(page, cursor->latch_mode, mtr); + + page_cur_set_before_first(next_page, btr_pcur_get_page_cur(cursor)); +} + +/************************************************************* +Moves the persistent cursor backward if it is on the first record of the page. +Commits mtr. Note that to prevent a possible deadlock, the operation +first stores the position of the cursor, commits mtr, acquires the necessary +latches and restores the cursor position again before returning. The +alphabetical position of the cursor is guaranteed to be sensible on +return, but it may happen that the cursor is not positioned on the last +record of any page, because the structure of the tree may have changed +during the time when the cursor had no latches. */ + +void +btr_pcur_move_backward_from_page( +/*=============================*/ + btr_pcur_t* cursor, /* in: persistent cursor, must be on the first + record of the current page */ + mtr_t* mtr) /* in: mtr */ +{ + ulint prev_page_no; + ulint space; + page_t* page; + page_t* prev_page; + ulint latch_mode; + ulint latch_mode2; + + ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + ut_ad(btr_pcur_is_before_first_on_page(cursor, mtr)); + ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr)); + + latch_mode = cursor->latch_mode; + + if (latch_mode == BTR_SEARCH_LEAF) { + + latch_mode2 = BTR_SEARCH_PREV; + + } else if (latch_mode == BTR_MODIFY_LEAF) { + + latch_mode2 = BTR_MODIFY_PREV; + } else { + ut_error; + } + + btr_pcur_store_position(cursor, mtr); + + mtr_commit(mtr); + + mtr_start(mtr); + + btr_pcur_restore_position(latch_mode2, cursor, mtr); + + page = btr_pcur_get_page(cursor); + + prev_page_no = btr_page_get_prev(page, mtr); + space = buf_frame_get_space_id(page); + + if (btr_pcur_is_before_first_on_page(cursor, mtr) + && (prev_page_no != FIL_NULL)) { + + prev_page = btr_pcur_get_btr_cur(cursor)->left_page; + + btr_leaf_page_release(page, latch_mode, mtr); + + page_cur_set_after_last(prev_page, + btr_pcur_get_page_cur(cursor)); + } else if (prev_page_no != FIL_NULL) { + + /* The repositioned cursor did not end on an infimum record on + a page. Cursor repositioning acquired a latch also on the + previous page, but we do not need the latch: release it. */ + + prev_page = btr_pcur_get_btr_cur(cursor)->left_page; + + btr_leaf_page_release(prev_page, latch_mode, mtr); + } + + cursor->latch_mode = latch_mode; + + cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; +} + +/************************************************************* +Moves the persistent cursor to the previous record in the tree. If no records +are left, the cursor stays 'before first in tree'. */ + +ibool +btr_pcur_move_to_prev( +/*==================*/ + /* out: TRUE if the cursor was not before first + in tree */ + btr_pcur_t* cursor, /* in: persistent cursor; NOTE that the + function may release the page latch */ + mtr_t* mtr) /* in: mtr */ +{ + ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + + cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; + + if (btr_pcur_is_before_first_on_page(cursor, mtr)) { + + if (btr_pcur_is_before_first_in_tree(cursor, mtr)) { + + return(FALSE); + } + + btr_pcur_move_backward_from_page(cursor, mtr); + + return(TRUE); + } + + btr_pcur_move_to_prev_on_page(cursor, mtr); + + return(TRUE); +} + +/****************************************************************** +If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first +user record satisfying the search condition, in the case PAGE_CUR_L or +PAGE_CUR_LE, on the last user record. If no such user record exists, then +in the first case sets the cursor after last in tree, and in the latter case +before first in tree. The latching mode must be BTR_SEARCH_LEAF or +BTR_MODIFY_LEAF. */ + +void +btr_pcur_open_on_user_rec( +/*======================*/ + dict_index_t* index, /* in: index */ + dtuple_t* tuple, /* in: tuple on which search done */ + ulint mode, /* in: PAGE_CUR_L, ... */ + ulint latch_mode, /* in: BTR_SEARCH_LEAF or + BTR_MODIFY_LEAF */ + btr_pcur_t* cursor, /* in: memory buffer for persistent + cursor */ + mtr_t* mtr) /* in: mtr */ +{ + btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr); + + if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) { + + if (btr_pcur_is_after_last_on_page(cursor, mtr)) { + + btr_pcur_move_to_next_user_rec(cursor, mtr); + } + } else { + ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L)); + + /* Not implemented yet */ + + ut_error; + } +} diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c new file mode 100644 index 00000000000..89e396013fa --- /dev/null +++ b/innobase/btr/btr0sea.c @@ -0,0 +1,1436 @@ +/************************************************************************ +The index tree adaptive search + +(c) 1996 Innobase Oy + +Created 2/17/1996 Heikki Tuuri +*************************************************************************/ + +#include "btr0sea.h" +#ifdef UNIV_NONINL +#include "btr0sea.ic" +#endif + +#include "buf0buf.h" +#include "page0page.h" +#include "page0cur.h" +#include "btr0cur.h" +#include "btr0btr.h" + +ulint btr_search_n_succ = 0; +ulint btr_search_n_hash_fail = 0; + +byte btr_sea_pad1[64]; /* padding to prevent other memory update + hotspots from residing on the same memory + cache line as btr_search_latch */ + +/* The latch protecting the adaptive search system: this latch protects the +(1) positions of records on those pages where a hash index has been built. +NOTE: It does not protect values of non-ordering fields within a record from +being updated in-place! We can use fact (1) to perform unique searches to +indexes. */ + +rw_lock_t* btr_search_latch_temp; /* We will allocate the latch from + dynamic memory to get it to the + same DRAM page as other hotspot + semaphores */ + +byte btr_sea_pad2[64]; /* padding to prevent other memory update + hotspots from residing on the same memory + cache line */ + +btr_search_sys_t* btr_search_sys; + +/* If the number of records on the page divided by this parameter +would have been successfully accessed using a hash index, the index +is then built on the page, assuming the global limit has been reached */ + +#define BTR_SEARCH_PAGE_BUILD_LIMIT 16 + +/* The global limit for consecutive potentially successful hash searches, +before hash index building is started */ + +#define BTR_SEARCH_BUILD_LIMIT 100 + +/************************************************************************ +Builds a hash index on a page with the given parameters. If the page already +has a hash index with different parameters, the old hash index is removed. */ +static +void +btr_search_build_page_hash_index( +/*=============================*/ + page_t* page, /* in: index page, s- or x-latched */ + ulint n_fields, /* in: hash this many full fields */ + ulint n_bytes, /* in: hash this many bytes from the next + field */ + ulint side); /* in: hash for searches from this side */ + +/********************************************************************* +This function should be called before reserving any btr search mutex, if +the intended operation might add nodes to the search system hash table. +Because of the latching order, once we have reserved the btr search system +latch, we cannot allocate a free frame from the buffer pool. Checks that +there is a free buffer frame allocated for hash table heap in the btr search +system. If not, allocates a free frames for the heap. This check makes it +probable that, when have reserved the btr search system latch and we need to +allocate a new node to the hash table, it will succeed. However, the check +will not guarantee success. */ +static +void +btr_search_check_free_space_in_heap(void) +/*=====================================*/ +{ + buf_frame_t* frame; + hash_table_t* table; + mem_heap_t* heap; + + ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED) + && !rw_lock_own(&btr_search_latch, RW_LOCK_EX)); + + table = btr_search_sys->hash_index; + + heap = table->heap; + + /* Note that we peek the value of heap->free_block without reserving + the latch: this is ok, because we will not guarantee that there will + be enough free space in the hash table. */ + + if (heap->free_block == NULL) { + frame = buf_frame_alloc(); + + rw_lock_x_lock(&btr_search_latch); + + if (heap->free_block == NULL) { + heap->free_block = frame; + } else { + buf_frame_free(frame); + } + + rw_lock_x_unlock(&btr_search_latch); + } +} + +/********************************************************************* +Creates and initializes the adaptive search system at a database start. */ + +void +btr_search_sys_create( +/*==================*/ + ulint hash_size) /* in: hash index hash table size */ +{ + /* We allocate the search latch from dynamic memory: + see above at the global variable definition */ + + btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t)); + + rw_lock_create(&btr_search_latch); + + btr_search_sys = mem_alloc(sizeof(btr_search_sys_t)); + + btr_search_sys->hash_index = ha_create(TRUE, hash_size, 0, 0); + + rw_lock_set_level(&btr_search_latch, SYNC_SEARCH_SYS); +} + +/********************************************************************* +Creates and initializes a search info struct. */ + +btr_search_t* +btr_search_info_create( +/*===================*/ + /* out, own: search info struct */ + mem_heap_t* heap) /* in: heap where created */ +{ + btr_search_t* info; + + info = mem_heap_alloc(heap, sizeof(btr_search_t)); + + info->last_search = NULL; + info->n_direction = 0; + info->root_guess = NULL; + + info->hash_analysis = 0; + info->n_hash_potential = 0; + + info->last_hash_succ = FALSE; + + info->n_hash_succ = 0; + info->n_hash_fail = 0; + info->n_patt_succ = 0; + info->n_searches = 0; + + return(info); +} + +/************************************************************************* +Updates the search info of an index about hash successes. */ +static +void +btr_search_info_update_hash( +/*========================*/ + btr_search_t* info, /* in: search info */ + btr_cur_t* cursor) /* in: cursor which was just positioned */ +{ + dict_index_t* index; + ulint n_unique; + int cmp; + + ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED) + && !rw_lock_own(&btr_search_latch, RW_LOCK_EX)); + + index = cursor->index; + + if (index->type & DICT_IBUF) { + /* So many deletes are performed on an insert buffer tree + that we do not consider a hash index useful on it: */ + + return; + } + + if (info->n_hash_potential == 0) { + + goto set_new_recomm; + } + + n_unique = dict_index_get_n_unique_in_tree(index); + + /* Test if the search would have succeeded using the recommended + hash prefix */ + + if ((info->n_fields >= n_unique) && (cursor->up_match >= n_unique)) { + + info->n_hash_potential++; + + return; + } + + cmp = ut_pair_cmp(info->n_fields, info->n_bytes, + cursor->low_match, cursor->low_bytes); + + if (((info->side == BTR_SEARCH_LEFT_SIDE) && (cmp <= 0)) + || ((info->side == BTR_SEARCH_RIGHT_SIDE) && (cmp > 0))) { + + goto set_new_recomm; + } + + cmp = ut_pair_cmp(info->n_fields, info->n_bytes, + cursor->up_match, cursor->up_bytes); + + if (((info->side == BTR_SEARCH_LEFT_SIDE) && (cmp > 0)) + || ((info->side == BTR_SEARCH_RIGHT_SIDE) && (cmp <= 0))) { + + goto set_new_recomm; + } + + info->n_hash_potential++; + + return; + +set_new_recomm: + /* We have to set a new recommendation; skip the hash analysis + for a while to avoid unnecessary CPU time usage when there is no + chance for success */ + + info->hash_analysis = 0; + + if ((cursor->up_match >= n_unique) + || (cursor->low_match >= n_unique)) { + info->n_fields = n_unique; + info->n_bytes = 0; + + info->side = BTR_SEARCH_LEFT_SIDE; + } + + cmp = ut_pair_cmp(cursor->up_match, cursor->up_bytes, + cursor->low_match, cursor->low_bytes); + if (cmp == 0) { + info->n_hash_potential = 0; + + } else if (cmp > 0) { + info->n_hash_potential = 1; + + if (cursor->up_match >= n_unique) { + + info->n_fields = n_unique; + info->n_bytes = 0; + + } else if (cursor->low_match < cursor->up_match) { + + info->n_fields = cursor->low_match + 1; + info->n_bytes = 0; + } else { + info->n_fields = cursor->low_match; + info->n_bytes = cursor->low_bytes + 1; + } + + info->side = BTR_SEARCH_LEFT_SIDE; + } else { + info->n_hash_potential = 1; + + if (cursor->low_match >= n_unique) { + + info->n_fields = n_unique; + info->n_bytes = 0; + + } else if (cursor->low_match > cursor->up_match) { + + info->n_fields = cursor->up_match + 1; + info->n_bytes = 0; + } else { + info->n_fields = cursor->up_match; + info->n_bytes = cursor->up_bytes + 1; + } + + info->side = BTR_SEARCH_RIGHT_SIDE; + } +} + +/************************************************************************* +Updates the block search info on hash successes. */ +static +ibool +btr_search_update_block_hash_info( +/*==============================*/ + /* out: TRUE if building a (new) hash index on + the block is recommended */ + btr_search_t* info, /* in: search info */ + buf_block_t* block, /* in: buffer block */ + btr_cur_t* cursor) /* in: cursor */ +{ + ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED) + && !rw_lock_own(&btr_search_latch, RW_LOCK_EX)); + ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED) + || rw_lock_own(&(block->lock), RW_LOCK_EX)); + ut_ad(cursor); + + info->last_hash_succ = FALSE; + + if ((block->n_hash_helps > 0) + && (info->n_hash_potential > 0) + && (block->n_fields == info->n_fields) + && (block->n_bytes == info->n_bytes) + && (block->side == info->side)) { + + if ((block->is_hashed) + && (block->curr_n_fields == info->n_fields) + && (block->curr_n_bytes == info->n_bytes) + && (block->curr_side == info->side)) { + + /* The search would presumably have succeeded using + the hash index */ + + info->last_hash_succ = TRUE; + } + + block->n_hash_helps++; + } else { + block->n_hash_helps = 1; + block->n_fields = info->n_fields; + block->n_bytes = info->n_bytes; + block->side = info->side; + } + + if (cursor->index->table->does_not_fit_in_memory) { + block->n_hash_helps = 0; + } + + if ((block->n_hash_helps > page_get_n_recs(block->frame) + / BTR_SEARCH_PAGE_BUILD_LIMIT) + && (info->n_hash_potential >= BTR_SEARCH_BUILD_LIMIT)) { + + if ((!block->is_hashed) + || (block->n_hash_helps + > 2 * page_get_n_recs(block->frame)) + || (block->n_fields != block->curr_n_fields) + || (block->n_bytes != block->curr_n_bytes) + || (block->side != block->curr_side)) { + + /* Build a new hash index on the page */ + + return(TRUE); + } + } + + return(FALSE); +} + +/************************************************************************* +Updates a hash node reference when it has been unsuccessfully used in a +search which could have succeeded with the used hash parameters. This can +happen because when building a hash index for a page, we do not check +what happens at page boundaries, and therefore there can be misleading +hash nodes. Also, collisions in the fold value can lead to misleading +references. This function lazily fixes these imperfections in the hash +index. */ +static +void +btr_search_update_hash_ref( +/*=======================*/ + btr_search_t* info, /* in: search info */ + buf_block_t* block, /* in: buffer block where cursor positioned */ + btr_cur_t* cursor) /* in: cursor */ +{ + ulint fold; + rec_t* rec; + dulint tree_id; + + ut_ad(cursor->flag == BTR_CUR_HASH_FAIL); + ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); + ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED) + || rw_lock_own(&(block->lock), RW_LOCK_EX)); + if (block->is_hashed + && (info->n_hash_potential > 0) + && (block->curr_n_fields == info->n_fields) + && (block->curr_n_bytes == info->n_bytes) + && (block->curr_side == info->side)) { + + rec = btr_cur_get_rec(cursor); + + if (!page_rec_is_user_rec(rec)) { + + return; + } + + tree_id = ((cursor->index)->tree)->id; + + fold = rec_fold(rec, block->curr_n_fields, + block->curr_n_bytes, tree_id); + + ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); + + ha_insert_for_fold(btr_search_sys->hash_index, fold, rec); + } +} + +/************************************************************************* +Updates the search info. */ + +void +btr_search_info_update_slow( +/*========================*/ + btr_search_t* info, /* in: search info */ + btr_cur_t* cursor) /* in: cursor which was just positioned */ +{ + buf_block_t* block; + ibool build_index; + + ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED) + && !rw_lock_own(&btr_search_latch, RW_LOCK_EX)); + + block = buf_block_align(btr_cur_get_rec(cursor)); + + btr_search_info_update_hash(info, cursor); + + build_index = btr_search_update_block_hash_info(info, block, cursor); + + if (build_index || (cursor->flag == BTR_CUR_HASH_FAIL)) { + + btr_search_check_free_space_in_heap(); + } + + if (cursor->flag == BTR_CUR_HASH_FAIL) { + /* Update the hash node reference, if appropriate */ + + btr_search_n_hash_fail++; + + rw_lock_x_lock(&btr_search_latch); + + btr_search_update_hash_ref(info, block, cursor); + + rw_lock_x_unlock(&btr_search_latch); + } + + if (build_index) { + btr_search_build_page_hash_index(block->frame, + block->n_fields, + block->n_bytes, + block->side); + } +} + +/********************************************************************** +Checks if a guessed position for a tree cursor is right. Note that if +mode is PAGE_CUR_LE, which is used in inserts, and the function returns +TRUE, then cursor->up_match and cursor->low_match both have sensible values. */ +UNIV_INLINE +ibool +btr_search_check_guess( +/*===================*/ + /* out: TRUE if success */ + btr_cur_t* cursor, /* in: guessed cursor position */ + dtuple_t* tuple, /* in: data tuple */ + ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, + or PAGE_CUR_GE */ + mtr_t* mtr) /* in: mtr */ +{ + page_t* page; + rec_t* rec; + rec_t* prev_rec; + rec_t* next_rec; + ulint n_unique; + ulint match; + ulint bytes; + int cmp; + + n_unique = dict_index_get_n_unique_in_tree(cursor->index); + + rec = btr_cur_get_rec(cursor); + page = buf_frame_align(rec); + + ut_ad(page_rec_is_user_rec(rec)); + + match = 0; + bytes = 0; + + cmp = page_cmp_dtuple_rec_with_match(tuple, rec, &match, &bytes); + + if (mode == PAGE_CUR_GE) { + if (cmp == 1) { + + return(FALSE); + } + + cursor->up_match = match; + + if (match >= n_unique) { + + return(TRUE); + } + } else if (mode == PAGE_CUR_LE) { + if (cmp == -1) { + + return(FALSE); + } + + cursor->low_match = match; + + } else if (mode == PAGE_CUR_G) { + if (cmp != -1) { + + return(FALSE); + } + } else if (mode == PAGE_CUR_L) { + if (cmp != 1) { + + return(FALSE); + } + } + + match = 0; + bytes = 0; + + if ((mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE)) { + + ut_ad(rec != page_get_infimum_rec(page)); + + prev_rec = page_rec_get_prev(rec); + + if (prev_rec == page_get_infimum_rec(page)) { + + if (btr_page_get_prev(page, mtr) != FIL_NULL) { + + return(FALSE); + } + + return(TRUE); + } + + cmp = page_cmp_dtuple_rec_with_match(tuple, prev_rec, + &match, &bytes); + if (mode == PAGE_CUR_GE) { + if (cmp != 1) { + + return(FALSE); + } + } else { + if (cmp == -1) { + + return(FALSE); + } + } + + return(TRUE); + } + + ut_ad(rec != page_get_supremum_rec(page)); + + next_rec = page_rec_get_next(rec); + + if (next_rec == page_get_supremum_rec(page)) { + + if (btr_page_get_next(page, mtr) == FIL_NULL) { + + cursor->up_match = 0; + + return(TRUE); + } + + return(FALSE); + } + + cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec, &match, &bytes); + + if (mode == PAGE_CUR_LE) { + if (cmp != -1) { + + return(FALSE); + } + + cursor->up_match = match; + } else { + if (cmp == 1) { + + return(FALSE); + } + } + + return(TRUE); +} + +/********************************************************************** +Tries to guess the right search position based on the hash search info +of the index. Note that if mode is PAGE_CUR_LE, which is used in inserts, +and the function returns TRUE, then cursor->up_match and cursor->low_match +both have sensible values. */ + +ibool +btr_search_guess_on_hash( +/*=====================*/ + /* out: TRUE if succeeded */ + dict_index_t* index, /* in: index */ + btr_search_t* info, /* in: index search info */ + dtuple_t* tuple, /* in: logical record */ + ulint mode, /* in: PAGE_CUR_L, ... */ + ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */ + btr_cur_t* cursor, /* out: tree cursor */ + ulint has_search_latch,/* in: latch mode the caller + currently has on btr_search_latch: + RW_S_LATCH, RW_X_LATCH, or 0 */ + mtr_t* mtr) /* in: mtr */ +{ + buf_block_t* block; + rec_t* rec; + page_t* page; + ibool success; + ulint fold; + ulint tuple_n_fields; + dulint tree_id; +#ifdef notdefined + btr_cur_t cursor2; +#endif + ut_ad(index && info && tuple && cursor && mtr); + ut_ad((latch_mode == BTR_SEARCH_LEAF) + || (latch_mode == BTR_MODIFY_LEAF)); + + /* Note that, for efficiency, the struct info may not be protected by + any latch here! */ + + if (info->n_hash_potential == 0) { + + return(FALSE); + } + + cursor->n_fields = info->n_fields; + cursor->n_bytes = info->n_bytes; + + tuple_n_fields = dtuple_get_n_fields(tuple); + + if (tuple_n_fields < cursor->n_fields) { + + return(FALSE); + } + + if ((cursor->n_bytes > 0) && (tuple_n_fields <= cursor->n_fields)) { + + return(FALSE); + } + + tree_id = (index->tree)->id; + +#ifdef UNIV_SEARCH_PERF_STAT + info->n_hash_succ++; +#endif + fold = dtuple_fold(tuple, cursor->n_fields, cursor->n_bytes, tree_id); + + cursor->fold = fold; + cursor->flag = BTR_CUR_HASH; + + if (!has_search_latch) { + rw_lock_s_lock(&btr_search_latch); + } + + rec = ha_search_and_get_data(btr_search_sys->hash_index, fold); + + if (!rec) { + if (!has_search_latch) { + rw_lock_s_unlock(&btr_search_latch); + } + + goto failure; + } + + page = buf_frame_align(rec); + + if (!has_search_latch) { + + success = buf_page_get_known_nowait(latch_mode, page, + BUF_MAKE_YOUNG, +#ifdef UNIV_SYNC_DEBUG + __FILE__, __LINE__, +#endif + mtr); + + rw_lock_s_unlock(&btr_search_latch); + + if (!success) { + + goto failure; + } + + buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH); + } + + block = buf_block_align(page); + + if (block->state == BUF_BLOCK_REMOVE_HASH) { + if (!has_search_latch) { + + btr_leaf_page_release(page, latch_mode, mtr); + } + + goto failure; + } + + ut_ad(block->state == BUF_BLOCK_FILE_PAGE); + ut_ad(page_rec_is_user_rec(rec)); + + btr_cur_position(index, rec, cursor); + + /* Check the validity of the guess within the page */ + + if (0 != ut_dulint_cmp(tree_id, btr_page_get_index_id(page))) { + + success = FALSE; +/* + printf("Tree id %lu, page index id %lu fold %lu\n", + ut_dulint_get_low(tree_id), + ut_dulint_get_low(btr_page_get_index_id(page)), + fold); +*/ + } else { + success = btr_search_check_guess(cursor, tuple, mode, mtr); + } + + if (!success) { + btr_leaf_page_release(page, latch_mode, mtr); + + goto failure; + } + + if (info->n_hash_potential < BTR_SEARCH_BUILD_LIMIT + 5) { + + info->n_hash_potential++; + } + + if (info->last_hash_succ != TRUE) { + info->last_hash_succ = TRUE; + } + +#ifdef notdefined + /* These lines of code can be used in a debug version to check + correctness of the searched cursor position: */ + + info->last_hash_succ = FALSE; + + /* Currently, does not work if the following fails: */ + ut_a(!has_search_latch); + + btr_leaf_page_release(page, latch_mode, mtr); + + btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode, + &cursor2, 0, mtr); + ut_a(btr_cur_get_rec(&cursor2) == btr_cur_get_rec(cursor)); + + info->last_hash_succ = TRUE; +#endif + +#ifdef UNIV_SEARCH_PERF_STAT + btr_search_n_succ++; +#endif + if (!has_search_latch && buf_block_peek_if_too_old(block)) { + + buf_page_make_young(page); + } + + return(TRUE); + + /*-------------------------------------------*/ +failure: + info->n_hash_fail++; + + cursor->flag = BTR_CUR_HASH_FAIL; + +#ifdef UNIV_SEARCH_PERF_STAT + if (info->n_hash_succ > 0) { + info->n_hash_succ--; + } +#endif + info->last_hash_succ = FALSE; + + return(FALSE); +} + +/************************************************************************ +Drops a page hash index. */ + +void +btr_search_drop_page_hash_index( +/*============================*/ + page_t* page) /* in: index page, s- or x-latched */ +{ + hash_table_t* table; + buf_block_t* block; + ulint n_fields; + ulint n_bytes; + rec_t* rec; + rec_t* sup; + ulint fold; + ulint prev_fold; + dulint tree_id; + ulint n_cached; + ulint n_recs; + ulint* folds; + ulint i; + + ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED) + && !rw_lock_own(&btr_search_latch, RW_LOCK_EX)); + + rw_lock_s_lock(&btr_search_latch); + + block = buf_block_align(page); + + if (!block->is_hashed) { + + rw_lock_s_unlock(&btr_search_latch); + + return; + } + + table = btr_search_sys->hash_index; + + ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED) + || rw_lock_own(&(block->lock), RW_LOCK_EX) + || (block->buf_fix_count == 0)); + + n_fields = block->curr_n_fields; + n_bytes = block->curr_n_bytes; + + rw_lock_s_unlock(&btr_search_latch); + + n_recs = page_get_n_recs(page); + + /* Calculate and cache fold values into an array for fast deletion + from the hash index */ + + folds = mem_alloc(n_recs * sizeof(ulint)); + + n_cached = 0; + + sup = page_get_supremum_rec(page); + + rec = page_get_infimum_rec(page); + rec = page_rec_get_next(rec); + + tree_id = btr_page_get_index_id(page); + + prev_fold = 0; + + while (rec != sup) { + /* FIXME: in a mixed tree, not all records may have enough + ordering fields: */ + + fold = rec_fold(rec, n_fields, n_bytes, tree_id); + + if ((fold == prev_fold) && (prev_fold != 0)) { + + goto next_rec; + } + + /* Remove all hash nodes pointing to this page from the + hash chain */ + + folds[n_cached] = fold; + n_cached++; +next_rec: + rec = page_rec_get_next(rec); + } + + rw_lock_x_lock(&btr_search_latch); + + for (i = 0; i < n_cached; i++) { + + ha_remove_all_nodes_to_page(table, folds[i], page); + } + + block->is_hashed = FALSE; + + rw_lock_x_unlock(&btr_search_latch); + + mem_free(folds); +} + +/************************************************************************ +Drops a page hash index when a page is freed from a fseg to the file system. +Drops possible hash index if the page happens to be in the buffer pool. */ + +void +btr_search_drop_page_hash_when_freed( +/*=================================*/ + ulint space, /* in: space id */ + ulint page_no) /* in: page number */ +{ + ibool is_hashed; + page_t* page; + mtr_t mtr; + + is_hashed = buf_page_peek_if_search_hashed(space, page_no); + + if (!is_hashed) { + + return; + } + + mtr_start(&mtr); + + /* We assume that if the caller has a latch on the page, + then the caller has already drooped the hash index for the page, + and we never get here. Therefore we can acquire the s-latch to + the page without fearing a deadlock. */ + + page = buf_page_get(space, page_no, RW_S_LATCH, &mtr); + + buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH); + + btr_search_drop_page_hash_index(page); + + mtr_commit(&mtr); +} + +/************************************************************************ +Builds a hash index on a page with the given parameters. If the page already +has a hash index with different parameters, the old hash index is removed. */ +static +void +btr_search_build_page_hash_index( +/*=============================*/ + page_t* page, /* in: index page, s- or x-latched */ + ulint n_fields, /* in: hash this many full fields */ + ulint n_bytes, /* in: hash this many bytes from the next + field */ + ulint side) /* in: hash for searches from this side */ +{ + hash_table_t* table; + buf_block_t* block; + rec_t* rec; + rec_t* next_rec; + rec_t* sup; + ulint fold; + ulint next_fold; + dulint tree_id; + ulint n_cached; + ulint n_recs; + ulint* folds; + rec_t** recs; + ulint i; + + block = buf_block_align(page); + table = btr_search_sys->hash_index; + + ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX)); + ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED) + || rw_lock_own(&(block->lock), RW_LOCK_EX)); + + rw_lock_s_lock(&btr_search_latch); + + if (block->is_hashed && ((block->curr_n_fields != n_fields) + || (block->curr_n_bytes != n_bytes) + || (block->curr_side != side))) { + + rw_lock_s_unlock(&btr_search_latch); + + btr_search_drop_page_hash_index(page); + } else { + rw_lock_s_unlock(&btr_search_latch); + } + + n_recs = page_get_n_recs(page); + + if (n_recs == 0) { + + return; + } + + /* Calculate and cache fold values and corresponding records into + an array for fast insertion to the hash index */ + + folds = mem_alloc(n_recs * sizeof(ulint)); + recs = mem_alloc(n_recs * sizeof(rec_t*)); + + n_cached = 0; + + tree_id = btr_page_get_index_id(page); + + sup = page_get_supremum_rec(page); + + rec = page_get_infimum_rec(page); + rec = page_rec_get_next(rec); + + /* FIXME: in a mixed tree, all records may not have enough ordering + fields: */ + + fold = rec_fold(rec, n_fields, n_bytes, tree_id); + + if (side == BTR_SEARCH_LEFT_SIDE) { + + folds[n_cached] = fold; + recs[n_cached] = rec; + n_cached++; + } + + for (;;) { + next_rec = page_rec_get_next(rec); + + if (next_rec == sup) { + + if (side == BTR_SEARCH_RIGHT_SIDE) { + + folds[n_cached] = fold; + recs[n_cached] = rec; + n_cached++; + } + + break; + } + + next_fold = rec_fold(next_rec, n_fields, n_bytes, tree_id); + + if (fold != next_fold) { + /* Insert an entry into the hash index */ + + if (side == BTR_SEARCH_LEFT_SIDE) { + + folds[n_cached] = next_fold; + recs[n_cached] = next_rec; + n_cached++; + } else { + folds[n_cached] = fold; + recs[n_cached] = rec; + n_cached++; + } + } + + rec = next_rec; + fold = next_fold; + } + + btr_search_check_free_space_in_heap(); + + rw_lock_x_lock(&btr_search_latch); + + if (block->is_hashed && ((block->curr_n_fields != n_fields) + || (block->curr_n_bytes != n_bytes) + || (block->curr_side != side))) { + + rw_lock_x_unlock(&btr_search_latch); + + mem_free(folds); + mem_free(recs); + + return; + } + + block->is_hashed = TRUE; + block->n_hash_helps = 0; + + block->curr_n_fields = n_fields; + block->curr_n_bytes = n_bytes; + block->curr_side = side; + + for (i = 0; i < n_cached; i++) { + + ha_insert_for_fold(table, folds[i], recs[i]); + } + + rw_lock_x_unlock(&btr_search_latch); + + mem_free(folds); + mem_free(recs); +} + +/************************************************************************ +Moves or deletes hash entries for moved records. If new_page is already hashed, +then the hash index for page, if any, is dropped. If new_page is not hashed, +and page is hashed, then a new hash index is built to new_page with the same +parameters as page (this often happens when a page is split). */ + +void +btr_search_move_or_delete_hash_entries( +/*===================================*/ + page_t* new_page, /* in: records are copied to this page */ + page_t* page) /* in: index page from which records were + copied, and the copied records will be deleted + from this page */ +{ + buf_block_t* block; + buf_block_t* new_block; + ulint n_fields; + ulint n_bytes; + ulint side; + + block = buf_block_align(page); + new_block = buf_block_align(new_page); + + ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX) + && rw_lock_own(&(new_block->lock), RW_LOCK_EX)); + + rw_lock_s_lock(&btr_search_latch); + + if (new_block->is_hashed) { + + rw_lock_s_unlock(&btr_search_latch); + + btr_search_drop_page_hash_index(page); + + return; + } + + if (block->is_hashed) { + + n_fields = block->curr_n_fields; + n_bytes = block->curr_n_bytes; + side = block->curr_side; + + new_block->n_fields = block->curr_n_fields; + new_block->n_bytes = block->curr_n_bytes; + new_block->side = block->curr_side; + + rw_lock_s_unlock(&btr_search_latch); + + btr_search_build_page_hash_index(new_page, n_fields, n_bytes, + side); + ut_a(n_fields == block->curr_n_fields); + ut_a(n_bytes == block->curr_n_bytes); + ut_a(side == block->curr_side); + + return; + } + + rw_lock_s_unlock(&btr_search_latch); +} + +/************************************************************************ +Updates the page hash index when a single record is deleted from a page. */ + +void +btr_search_update_hash_on_delete( +/*=============================*/ + btr_cur_t* cursor) /* in: cursor which was positioned on the + record to delete using btr_cur_search_..., + the record is not yet deleted */ +{ + hash_table_t* table; + buf_block_t* block; + rec_t* rec; + ulint fold; + dulint tree_id; + ibool found; + + rec = btr_cur_get_rec(cursor); + + block = buf_block_align(rec); + + ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); + + if (!block->is_hashed) { + + return; + } + + table = btr_search_sys->hash_index; + + tree_id = ((cursor->index)->tree)->id; + + fold = rec_fold(rec, block->curr_n_fields, block->curr_n_bytes, + tree_id); + rw_lock_x_lock(&btr_search_latch); + + found = ha_search_and_delete_if_found(table, fold, rec); + + rw_lock_x_unlock(&btr_search_latch); +} + +/************************************************************************ +Updates the page hash index when a single record is inserted on a page. */ + +void +btr_search_update_hash_node_on_insert( +/*==================================*/ + btr_cur_t* cursor) /* in: cursor which was positioned to the + place to insert using btr_cur_search_..., + and the new record has been inserted next + to the cursor */ +{ + hash_table_t* table; + buf_block_t* block; + rec_t* rec; + + rec = btr_cur_get_rec(cursor); + + block = buf_block_align(rec); + + ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); + + if (!block->is_hashed) { + + return; + } + + rw_lock_x_lock(&btr_search_latch); + + if ((cursor->flag == BTR_CUR_HASH) + && (cursor->n_fields == block->curr_n_fields) + && (cursor->n_bytes == block->curr_n_bytes) + && (block->curr_side == BTR_SEARCH_RIGHT_SIDE)) { + + table = btr_search_sys->hash_index; + + ha_search_and_update_if_found(table, cursor->fold, rec, + page_rec_get_next(rec)); + + rw_lock_x_unlock(&btr_search_latch); + } else { + rw_lock_x_unlock(&btr_search_latch); + + btr_search_update_hash_on_insert(cursor); + } +} + +/************************************************************************ +Updates the page hash index when a single record is inserted on a page. */ + +void +btr_search_update_hash_on_insert( +/*=============================*/ + btr_cur_t* cursor) /* in: cursor which was positioned to the + place to insert using btr_cur_search_..., + and the new record has been inserted next + to the cursor */ +{ + hash_table_t* table; + buf_block_t* block; + page_t* page; + rec_t* rec; + rec_t* ins_rec; + rec_t* next_rec; + dulint tree_id; + ulint fold; + ulint ins_fold; + ulint next_fold; + ulint n_fields; + ulint n_bytes; + ulint side; + ibool locked = FALSE; + + table = btr_search_sys->hash_index; + + btr_search_check_free_space_in_heap(); + + rec = btr_cur_get_rec(cursor); + + block = buf_block_align(rec); + + ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); + + if (!block->is_hashed) { + + return; + } + + tree_id = ((cursor->index)->tree)->id; + + n_fields = block->curr_n_fields; + n_bytes = block->curr_n_bytes; + side = block->curr_side; + + ins_rec = page_rec_get_next(rec); + next_rec = page_rec_get_next(ins_rec); + + page = buf_frame_align(rec); + + ins_fold = rec_fold(ins_rec, n_fields, n_bytes, tree_id); + + if (next_rec != page_get_supremum_rec(page)) { + next_fold = rec_fold(next_rec, n_fields, n_bytes, tree_id); + } + + if (rec != page_get_infimum_rec(page)) { + fold = rec_fold(rec, n_fields, n_bytes, tree_id); + + } else { + if (side == BTR_SEARCH_LEFT_SIDE) { + + rw_lock_x_lock(&btr_search_latch); + + locked = TRUE; + + ha_insert_for_fold(table, ins_fold, ins_rec); + } + + goto check_next_rec; + } + + if (fold != ins_fold) { + + if (!locked) { + + rw_lock_x_lock(&btr_search_latch); + + locked = TRUE; + } + + if (side == BTR_SEARCH_RIGHT_SIDE) { + ha_insert_for_fold(table, fold, rec); + } else { + ha_insert_for_fold(table, ins_fold, ins_rec); + } + } + +check_next_rec: + if (next_rec == page_get_supremum_rec(page)) { + + if (side == BTR_SEARCH_RIGHT_SIDE) { + + if (!locked) { + rw_lock_x_lock(&btr_search_latch); + + locked = TRUE; + } + + ha_insert_for_fold(table, ins_fold, ins_rec); + } + + goto function_exit; + } + + if (ins_fold != next_fold) { + + if (!locked) { + + rw_lock_x_lock(&btr_search_latch); + + locked = TRUE; + } + + if (side == BTR_SEARCH_RIGHT_SIDE) { + + ha_insert_for_fold(table, ins_fold, ins_rec); +/* + printf("Hash insert for %s, fold %lu\n", + cursor->index->name, ins_fold); +*/ + } else { + ha_insert_for_fold(table, next_fold, next_rec); + } + } + +function_exit: + if (locked) { + rw_lock_x_unlock(&btr_search_latch); + } +} + +/************************************************************************ +Prints info of the search system. */ + +void +btr_search_print_info(void) +/*=======================*/ +{ + printf("SEARCH SYSTEM INFO\n"); + + rw_lock_x_lock(&btr_search_latch); + + ha_print_info(btr_search_sys->hash_index); + + rw_lock_x_unlock(&btr_search_latch); +} + +/************************************************************************ +Prints info of searches on an index. */ + +void +btr_search_index_print_info( +/*========================*/ + dict_index_t* index) /* in: index */ +{ + btr_search_t* info; + + printf("INDEX SEARCH INFO\n"); + + rw_lock_x_lock(&btr_search_latch); + + info = btr_search_get_info(index); + + printf("Searches %lu, hash succ %lu, fail %lu, patt succ %lu\n", + info->n_searches, info->n_hash_succ, info->n_hash_fail, + info->n_patt_succ); + + printf("Total of page cur short succ for all indexes %lu\n", + page_cur_short_succ); + rw_lock_x_unlock(&btr_search_latch); +} + +/************************************************************************ +Prints info of searches on a table. */ + +void +btr_search_table_print_info( +/*========================*/ + char* name) /* in: table name */ +{ + dict_table_t* table; + dict_index_t* index; + + mutex_enter(&(dict_sys->mutex)); + + table = dict_table_get_low(name); + + ut_a(table); + + mutex_exit(&(dict_sys->mutex)); + + index = dict_table_get_first_index(table); + + while (index) { + btr_search_index_print_info(index); + + index = dict_table_get_next_index(index); + } +} + +/************************************************************************ +Validates the search system. */ + +ibool +btr_search_validate(void) +/*=====================*/ + /* out: TRUE if ok */ +{ + rw_lock_x_lock(&btr_search_latch); + + ut_a(ha_validate(btr_search_sys->hash_index)); + + rw_lock_x_unlock(&btr_search_latch); + + return(TRUE); +} diff --git a/innobase/btr/makefilewin b/innobase/btr/makefilewin new file mode 100644 index 00000000000..a5806b74a51 --- /dev/null +++ b/innobase/btr/makefilewin @@ -0,0 +1,16 @@ +include ..\include\makefile.i + +btr.lib: btr0cur.obj btr0btr.obj btr0pcur.obj btr0sea.obj + lib -out:..\libs\btr.lib btr0cur.obj btr0btr.obj btr0pcur.obj btr0sea.obj + +btr0cur.obj: btr0cur.c + $(CCOM) $(CFL) -c btr0cur.c + +btr0btr.obj: btr0btr.c + $(CCOM) $(CFL) -c btr0btr.c + +btr0sea.obj: btr0sea.c + $(CCOM) $(CFL) -c btr0sea.c + +btr0pcur.obj: btr0pcur.c + $(CCOM) $(CFL) -c btr0pcur.c diff --git a/innobase/btr/ts/isql.c b/innobase/btr/ts/isql.c new file mode 100644 index 00000000000..db56aa65a66 --- /dev/null +++ b/innobase/btr/ts/isql.c @@ -0,0 +1,312 @@ +/************************************************************************ +Test for the client: interactive SQL + +(c) 1996-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "univ.i" +#include "ib_odbc.h" +#include "mem0mem.h" +#include "sync0sync.h" +#include "os0thread.h" +#include "os0proc.h" +#include "os0sync.h" +#include "srv0srv.h" + +ulint n_exited = 0; + +char cli_srv_endpoint_name[100]; +char cli_user_name[100]; + +ulint n_warehouses = ULINT_MAX; +ulint n_customers_d = ULINT_MAX; +bool is_tpc_d = FALSE; +ulint n_rounds = ULINT_MAX; +ulint n_users = ULINT_MAX; +ulint startdate = 0; +ulint enddate = 0; +bool own_warehouse = FALSE; + +ulint mem_pool_size = ULINT_MAX; + +/************************************************************************* +Reads a keywords and a values from an initfile. In case of an error, exits +from the process. */ +static +void +cli_read_initfile( +/*==============*/ + FILE* initfile) /* in: file pointer */ +{ + char str_buf[10000]; + ulint ulint_val; + + srv_read_init_val(initfile, FALSE, "SRV_ENDPOINT_NAME", str_buf, + &ulint_val); + + ut_a(ut_strlen(str_buf) < COM_MAX_ADDR_LEN); + + ut_memcpy(cli_srv_endpoint_name, str_buf, COM_MAX_ADDR_LEN); + + srv_read_init_val(initfile, FALSE, "USER_NAME", str_buf, + &ulint_val); + ut_a(ut_strlen(str_buf) < COM_MAX_ADDR_LEN); + + ut_memcpy(cli_user_name, str_buf, COM_MAX_ADDR_LEN); + + srv_read_init_val(initfile, TRUE, "MEM_POOL_SIZE", str_buf, + &mem_pool_size); + + srv_read_init_val(initfile, TRUE, "N_WAREHOUSES", str_buf, + &n_warehouses); + + srv_read_init_val(initfile, TRUE, "N_CUSTOMERS_D", str_buf, + &n_customers_d); + + srv_read_init_val(initfile, TRUE, "IS_TPC_D", str_buf, + &is_tpc_d); + + srv_read_init_val(initfile, TRUE, "N_ROUNDS", str_buf, + &n_rounds); + + srv_read_init_val(initfile, TRUE, "N_USERS", str_buf, + &n_users); + + srv_read_init_val(initfile, TRUE, "STARTDATE", str_buf, + &startdate); + + srv_read_init_val(initfile, TRUE, "ENDDATE", str_buf, + &enddate); + + srv_read_init_val(initfile, TRUE, "OWN_WAREHOUSE", str_buf, + &own_warehouse); +} + +/************************************************************************* +Reads configuration info for the client. */ +static +void +cli_boot( +/*=====*/ + char* name) /* in: the initialization file name */ +{ + FILE* initfile; + + initfile = fopen(name, "r"); + + if (initfile == NULL) { + printf( + "Error in client booting: could not open initfile whose name is %s!\n", + name); + os_process_exit(1); + } + + cli_read_initfile(initfile); + + fclose(initfile); +} + +/********************************************************************* +Interactive SQL loop. */ +static +void +isql( +/*=*/ + FILE* inputfile) /* in: input file containing SQL strings, + or stdin */ +{ + HENV env; + HDBC conn; + RETCODE ret; + HSTMT sql_query; + ulint tm, oldtm; + char buf[1000]; + char* str; + ulint count; + ulint n_begins; + ulint len; + ulint n; + ulint i; + ulint n_lines; + + ret = SQLAllocEnv(&env); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocConnect(env, &conn); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLConnect(conn, (UCHAR*)cli_srv_endpoint_name, + (SWORD)ut_strlen(cli_srv_endpoint_name), + cli_user_name, + (SWORD)ut_strlen(cli_user_name), + (UCHAR*)"password", 8); + ut_a(ret == SQL_SUCCESS); + + printf("Connection established\n"); + + printf("Interactive SQL performs queries by first making a stored\n"); + printf("procedure from them, and then calling the procedure.\n"); + printf("Put a semicolon after each statement and\n"); + printf("end your query with two <enter>s.\n\n"); + printf("You can also give a single input file\n"); + printf("as a command line argument to isql.\n\n"); + printf("In the file separate SQL queries and procedure bodies\n"); + printf("by a single empty line. Do not write the final END; into\n"); + printf("a procedure body.\n\n"); + + count = 0; +loop: + count++; + n = 0; + n_lines = 0; + + sprintf(buf, "PROCEDURE P%s%lu () IS\nBEGIN ", cli_user_name, + count); + for (;;) { + len = ut_strlen(buf + n) - 1; + n += len; + + if (len == 0) { + break; + } else { + sprintf(buf + n, "\n"); + n++; + n_lines++; + } + + str = fgets(buf + n, 1000, inputfile); + + if ((str == NULL) && (inputfile != stdin)) { + /* Reached end-of-file: switch to input from + keyboard */ + + inputfile = stdin; + + break; + } + + ut_a(str); + } + + if (n_lines == 1) { + /* Empty procedure */ + + goto loop; + } + + /* If the statement is actually the body of a procedure, + erase the first BEGIN from the string: */ + + n_begins = 0; + + for (i = 0; i < n - 5; i++) { + + if (ut_memcmp(buf + i, "BEGIN", 5) == 0) { + + n_begins++; + } + } + + if (n_begins > 1) { + + for (i = 0; i < n - 5; i++) { + + if (ut_memcmp(buf + i, "BEGIN", 5) == 0) { + + /* Erase the first BEGIN: */ + ut_memcpy(buf + i, " ", 5); + + break; + } + } + } + + sprintf(buf + n, "END;\n"); + + printf("SQL procedure to execute:\n%s\n", buf); + + ret = SQLAllocStmt(conn, &sql_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(sql_query, (UCHAR*)buf, ut_strlen(buf)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(sql_query); + + ut_a(ret == SQL_SUCCESS); + + sprintf(buf, "{P%s%lu ()}", cli_user_name, count); + + ret = SQLAllocStmt(conn, &sql_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(sql_query, (UCHAR*)buf, ut_strlen(buf)); + + ut_a(ret == SQL_SUCCESS); + + printf("Starting to execute the query\n"); + + oldtm = ut_clock(); + + ret = SQLExecute(sql_query); + + tm = ut_clock(); + + printf("Wall time for query %lu milliseconds\n\n", tm - oldtm); + + ut_a(ret == SQL_SUCCESS); + + goto loop; +} + +/******************************************************************** +Main test function. */ + +void +main(int argc, char* argv[]) +/*========================*/ +{ + ulint tm, oldtm; + FILE* inputfile; + + if (argc > 2) { + printf("Only one input file allowed\n"); + + os_process_exit(1); + + } else if (argc == 2) { + inputfile = fopen(argv[1], "r"); + + if (inputfile == NULL) { + printf( + "Error: could not open the inputfile whose name is %s!\n", + argv[1]); + os_process_exit(1); + } + } else { + inputfile = stdin; + } + + cli_boot("cli_init"); + + sync_init(); + + mem_init(mem_pool_size); + + oldtm = ut_clock(); + + isql(inputfile); + + tm = ut_clock(); + + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/btr/ts/makefile b/innobase/btr/ts/makefile new file mode 100644 index 00000000000..58364717472 --- /dev/null +++ b/innobase/btr/ts/makefile @@ -0,0 +1,16 @@ +include ..\..\makefile.i + +doall: tssrv tscli isql + +tssrv: ..\btr.lib tssrv.c + $(CCOM) $(CFL) -I.. -I..\.. ..\btr.lib ..\..\eval.lib ..\..\ibuf.lib ..\..\trx.lib ..\..\pars.lib ..\..\que.lib ..\..\lock.lib ..\..\row.lib ..\..\read.lib ..\..\srv.lib ..\..\com.lib ..\..\usr.lib ..\..\thr.lib ..\..\fut.lib ..\..\fsp.lib ..\..\page.lib ..\..\dyn.lib ..\..\mtr.lib ..\..\log.lib ..\..\rem.lib ..\..\fil.lib ..\..\buf.lib ..\..\dict.lib ..\..\data.lib ..\..\mach.lib ..\..\ha.lib ..\..\ut.lib ..\..\sync.lib ..\..\mem.lib ..\..\os.lib tssrv.c $(LFL) + +tscli: ..\btr.lib tscli.c + $(CCOM) $(CFL) -I.. -I..\.. ..\btr.lib ..\..\ib_odbc.lib ..\..\eval.lib ..\..\ibuf.lib ..\..\trx.lib ..\..\pars.lib ..\..\que.lib ..\..\lock.lib ..\..\row.lib ..\..\read.lib ..\..\srv.lib ..\..\com.lib ..\..\usr.lib ..\..\thr.lib ..\..\fut.lib ..\..\fsp.lib ..\..\page.lib ..\..\dyn.lib ..\..\mtr.lib ..\..\log.lib ..\..\rem.lib ..\..\fil.lib ..\..\buf.lib ..\..\dict.lib ..\..\data.lib ..\..\mach.lib ..\..\ha.lib ..\..\ut.lib ..\..\sync.lib ..\..\mem.lib ..\..\os.lib tscli.c $(LFL) + +isql: ..\btr.lib isql.c + $(CCOM) $(CFL) -I.. -I..\.. ..\btr.lib ..\..\ib_odbc.lib ..\..\eval.lib ..\..\ibuf.lib ..\..\trx.lib ..\..\pars.lib ..\..\que.lib ..\..\lock.lib ..\..\row.lib ..\..\read.lib ..\..\srv.lib ..\..\com.lib ..\..\usr.lib ..\..\thr.lib ..\..\fut.lib ..\..\fsp.lib ..\..\page.lib ..\..\dyn.lib ..\..\mtr.lib ..\..\log.lib ..\..\rem.lib ..\..\fil.lib ..\..\buf.lib ..\..\dict.lib ..\..\data.lib ..\..\mach.lib ..\..\ha.lib ..\..\ut.lib ..\..\sync.lib ..\..\mem.lib ..\..\os.lib isql.c $(LFL) + +tsrecv: ..\btr.lib tsrecv.c + $(CCOM) $(CFL) -I.. -I..\.. ..\btr.lib ..\..\ibuf.lib ..\..\trx.lib ..\..\pars.lib ..\..\que.lib ..\..\lock.lib ..\..\row.lib ..\..\read.lib ..\..\srv.lib ..\..\com.lib ..\..\usr.lib ..\..\thr.lib ..\..\fut.lib ..\..\fsp.lib ..\..\page.lib ..\..\dyn.lib ..\..\mtr.lib ..\..\log.lib ..\..\rem.lib ..\..\fil.lib ..\..\buf.lib ..\..\dict.lib ..\..\data.lib ..\..\mach.lib ..\..\ha.lib ..\..\ut.lib ..\..\sync.lib ..\..\mem.lib ..\..\os.lib tsrecv.c $(LFL) + diff --git a/innobase/btr/ts/trash/TSIT.C b/innobase/btr/ts/trash/TSIT.C new file mode 100644 index 00000000000..775d4036c6d --- /dev/null +++ b/innobase/btr/ts/trash/TSIT.C @@ -0,0 +1,483 @@ +/************************************************************************ +The test module for the record manager of MVB. + +(c) 1994 Heikki Tuuri + +Created 1/25/1994 Heikki Tuuri +*************************************************************************/ + + +#include "rm0phr.h" +#include "rm0lgr.h" +#include "ut0ut.h" +#include "buf0mem.h" +#include "rm0ipg.h" +#include "../it0it.h" +#include "../it0hi.h" +#include "../it0ads.h" + +byte buf[100]; +byte buf2[100]; +lint lintbuf[2048]; + +byte numbuf[6000]; +byte numlogrecbuf[100]; +phr_record_t* qs_table[100000]; + +lint qs_comp = 0; + +extern +void +test1(void); + +#ifdef NOT_DEFINED + +void +q_sort(lint low, lint up) +{ + phr_record_t* temp, *pivot; + lint i, j; + + + pivot = qs_table[(low + up) / 2]; + + i = low; + j = up; + + while (i < j) { + qs_comp++; + if (cmp_phr_compare(qs_table[i], pivot)<= 0) { + i++; + } else { + j--; + temp = qs_table[i]; + qs_table[i] = qs_table[j]; + qs_table[j] = temp; + } + } + + if (j == up) { + temp = qs_table[(low + up) / 2]; + qs_table[(low + up) / 2] = qs_table[up - 1]; + qs_table[up - 1] = temp; + j--; + } + + + if (j - low <= 1) { + /* do nothing */ + } else if (j - low == 2) { + qs_comp++; + if (cmp_phr_compare(qs_table[low], + qs_table[low + 1]) + <= 0) { + /* do nothing */ + } else { + temp = qs_table[low]; + qs_table[low] = qs_table[low + 1]; + qs_table[low + 1] = temp; + } + } else { + q_sort(low, j); + } + + if (up - j <= 1) { + /* do nothing */ + } else if (up - j == 2) { + qs_comp++; + if (cmp_phr_compare(qs_table[j], + qs_table[j + 1]) + <= 0) { + /* do nothing */ + } else { + temp = qs_table[j]; + qs_table[j] = qs_table[j + 1]; + qs_table[j + 1] = temp; + } + } else { + q_sort(j, up); + } +} + +#endif + +extern +void +test1(void) +{ + phr_record_t* physrec; + phr_record_t* rec1; + phr_record_t* rec2; + lgr_record_t* logrec; + lgrf_field_t* logfield; + lint len; + byte* str; + lint len2; + lint tm; + lint oldtm; + lint i, j, k, l, m; + bool b; + it_cur_cursor_t cursor; + ipg_cur_cursor_t* page_cursor; + ipg_page_t* page; + + byte c4, c3, c2, c1, c0; + lint rand, rnd1, rnd2; + byte* nb; + lgr_record_t* numlogrec; + byte* pgbuf; + mem_stream_t* stream; + lint tree1, tree2, tree3; + lint dummy1, dummy2; + + pgbuf = (byte*)lintbuf; + + stream = mem_stream_create(0); + + printf("-------------------------------------------\n"); + printf("TEST 1. Speed and basic tests.\n"); + + logrec = lgr_create_logical_record(stream, 2); + + nb = numbuf; + + c4 = '0'; + c3 = '0'; + for (c2 = '0'; c2 <= '9'; c2++) { + for (c1 = '0'; c1 <= '9'; c1++) { + for (c0 = '0'; c0 <= '9'; c0++) { + *nb = c4; nb++; + *nb = c3; nb++; + *nb = c2; nb++; + *nb = c1; nb++; + *nb = c0; nb++; + *nb = '\0'; nb++; + } + } + } + + numlogrec = lgr_create_logical_record(stream, 2); + + + tree1 = it_create_index_tree(); + + oldtm = ut_clock(); + + rand = 99900; + rnd1 = 67; + for (j = 0; j < 1; j++) { + for (i = 0 ; i < 100000; i++) { + + rand = (rand + 1) % 100000; + + logfield = lgr_get_nth_field(numlogrec, 0); + lgrf_set_data(logfield, numbuf + 6 * (rand / 300)); + lgrf_set_len(logfield, 6); + + logfield = lgr_get_nth_field(numlogrec, 1); + lgrf_set_data(logfield, numbuf + 6 * (rand % 300)); + lgrf_set_len(logfield, 6); +/* + it_insert(tree1, numlogrec); +*/ + + + + it_cur_search_tree_to_nth_level(tree1, 1, numlogrec, + IPG_SE_L_GE, &cursor, &dummy1, &dummy2); + +/* + it_cur_set_to_first(tree1, &cursor); +*/ + + it_cur_insert_record(&cursor, numlogrec); + + } + } + tm = ut_clock(); + printf("Time for inserting %ld recs = %ld \n", i* j, tm - oldtm); + +/* it_print_tree(tree1, 10);*/ + hi_print_info(); + ads_print_info(); +/* + oldtm = ut_clock(); + + rand = 11113; + for (i = 0; i < 5000; i++) { + + rand = (rand + 57123) % 100000; + + logfield = lgr_get_nth_field(numlogrec, 0); + lgrf_set_data(logfield, numbuf + 6 * (rand / 300)); + lgrf_set_len(logfield, 6); + + logfield = lgr_get_nth_field(numlogrec, 1); + lgrf_set_data(logfield, numbuf + 6 * (rand % 300)); + lgrf_set_len(logfield, 6); + + it_cur_search_tree_to_nth_level(tree1, 1, numlogrec, + IPG_SE_L_GE, &cursor, &dummy1, &dummy2); + + } + tm = ut_clock(); + printf("Time for searching %ld recs = %ld \n", i, tm - oldtm); +*/ + + it_cur_set_to_first(tree1, &cursor); + + rec1 = ipg_cur_get_record(it_cur_get_page_cursor(&cursor)); + + for (i = 0;; i++) { + it_cur_move_to_next(&cursor); + if (it_cur_end_of_level(&cursor)) { + break; + } + rec2 = ipg_cur_get_record(it_cur_get_page_cursor(&cursor)); + ut_a(cmp_phr_compare(rec1, rec2) == -1); + rec1 = rec2; + } + + printf("tree1 checked for right sorted order!\n"); + +#ifdef not_defined + + oldtm = ut_clock(); + + for (j = 0; j < 1; j++) { + rand = 11113; + for (i = 0; i < 3000; i++) { + + rand = (rand + 57123) % 100000; + + logfield = lgr_get_nth_field(numlogrec, 0); + lgrf_set_data(logfield, numbuf + 6 * (rand / 300)); + lgrf_set_len(logfield, 6); + + logfield = lgr_get_nth_field(numlogrec, 1); + lgrf_set_data(logfield, numbuf + 6 * (rand % 300)); + lgrf_set_len(logfield, 6); + + physrec = hi_search(numlogrec); + + ut_a(physrec); + } + + } + ut_a(physrec); + tm = ut_clock(); + printf("Time for hi_search %ld recs = %ld \n", i * j, + tm - oldtm); + + + + oldtm = ut_clock(); + + for (i = 0; i < 100000; i++) { +/* j += lgr_fold(numlogrec, -1, -1);*/ +/* b += phr_lgr_equal(physrec, numlogrec, -1);*/ + k += ut_hash_lint(j, HI_TABLE_SIZE); + } + + +/* ut_a(b);*/ + tm = ut_clock(); + printf("Time for fold + equal %ld recs %s = %ld \n", i, physrec, + tm - oldtm); + + printf("%ld %ld %ld\n", j, b, k); + + hi_print_info(); + + tree2 = it_create_index_tree(); + + rand = 90000; + for (i = 0; i < 300; i++) { + + rand = (rand + 1) % 100000; + + logfield = lgr_get_nth_field(numlogrec, 0); + lgrf_set_data(logfield, numbuf + 6 * (rand / 300)); + lgrf_set_len(logfield, 6); + + logfield = lgr_get_nth_field(numlogrec, 1); + lgrf_set_data(logfield, numbuf + 6 * (rand % 300)); + lgrf_set_len(logfield, 6); + + it_cur_search_tree_to_nth_level(tree2, 1, numlogrec, + IPG_SE_L_GE, &cursor); + + it_cur_insert_record(&cursor, numlogrec); + + } + + oldtm = ut_clock(); + + rand = 10000; + for (i = 0; i < 3000; i++) { + + rand = (rand + 1) % 100000; + + logfield = lgr_get_nth_field(numlogrec, 0); + lgrf_set_data(logfield, numbuf + 6 * (rand / 300)); + lgrf_set_len(logfield, 6); + + logfield = lgr_get_nth_field(numlogrec, 1); + lgrf_set_data(logfield, numbuf + 6 * (rand % 300)); + lgrf_set_len(logfield, 6); + + it_cur_search_tree_to_nth_level(tree2, 1, numlogrec, + IPG_SE_L_GE, &cursor); + + it_cur_insert_record(&cursor, numlogrec); + + } + tm = ut_clock(); + printf("Time for inserting sequentially %ld recs = %ld \n", + i, tm - oldtm); + + +/* it_print_tree(tree2, 10); */ + + + tree3 = it_create_index_tree(); + + rand = 0; + for (i = 0; i < 300; i++) { + + rand = (rand + 1) % 100000; + + logfield = lgr_get_nth_field(numlogrec, 0); + lgrf_set_data(logfield, numbuf + 6 * (rand / 300)); + lgrf_set_len(logfield, 6); + + logfield = lgr_get_nth_field(numlogrec, 1); + lgrf_set_data(logfield, numbuf + 6 * (rand % 300)); + lgrf_set_len(logfield, 6); + + it_cur_search_tree_to_nth_level(tree3, 1, numlogrec, + IPG_SE_L_GE, &cursor); + + it_cur_insert_record(&cursor, numlogrec); + + } + + oldtm = ut_clock(); + + rand = 100000; + for (i = 0; i < 3000; i++) { + + rand = (rand - 1) % 100000; + + logfield = lgr_get_nth_field(numlogrec, 0); + lgrf_set_data(logfield, numbuf + 6 * (rand / 300)); + lgrf_set_len(logfield, 6); + + logfield = lgr_get_nth_field(numlogrec, 1); + lgrf_set_data(logfield, numbuf + 6 * (rand % 300)); + lgrf_set_len(logfield, 6); + + it_cur_search_tree_to_nth_level(tree3, 1, numlogrec, + IPG_SE_L_GE, &cursor); + + it_cur_insert_record(&cursor, numlogrec); + + } + tm = ut_clock(); + printf("Time for inserting sequentially downw. %ld recs = %ld \n", + i, tm - oldtm); + + +/* it_print_tree(tree3, 10); */ + +#endif + +} + +#ifdef NOT_DEFINED + +/* Test of quicksort */ +void +test2(void) +{ + mem_stream_t* stream; + byte* stbuf; + lgrf_field_t* logfield; + lint tm; + lint oldtm; + lint i, j, k, l, m; + lint rand; + lgr_record_t* numlogrec; + phr_record_t* ph_rec; + + stream = mem_stream_create(1000); + + numlogrec = lgr_create_logical_record(stream, 2); + + oldtm = ut_clock(); + + rand = 11113; + for (i = 0; i < 50000; i++) { + stbuf = mem_stream_alloc(stream, 30); + + rand = (rand + 57123) % 100000; + + logfield = lgr_get_nth_field(numlogrec, 0); + lgrf_set_data(logfield, numbuf + 6 * (rand / 300)); + lgrf_set_len(logfield, 6); + + logfield = lgr_get_nth_field(numlogrec, 1); + lgrf_set_data(logfield, numbuf + 6 * (rand % 300)); + lgrf_set_len(logfield, 6); + + ph_rec = phr_create_physical_record(stbuf, 30, numlogrec); + + qs_table[i] = ph_rec; + + } + tm = ut_clock(); + printf("Time for inserting %ld recs to mem stream = %ld \n", + i, tm - oldtm); + + + oldtm = ut_clock(); + + q_sort(0, 50000); + + tm = ut_clock(); + printf("Time for quicksort of %ld recs = %ld, comps: %ld \n", + i, tm - oldtm, qs_comp); + + + + for (i = 1; i < 49999; i++) { + ut_a(-1 == + cmp_phr_compare(qs_table[i], qs_table[i+1] + )); + } + tm = ut_clock(); + + + oldtm = ut_clock(); + for (i = 1; i < 50000; i++) { + k += cmp_phr_compare(qs_table[i & 0xF], + qs_table[5]); + } + tm = ut_clock(); + printf("%ld\n", k); + + printf("Time for cmp of %ld ph_recs = %ld \n", + i, tm - oldtm); + + mem_stream_free(stream); + +} +#endif + +void +main(void) +{ + test1(); +/* test2(); */ +} + diff --git a/innobase/btr/ts/trash/tsbtrold5.c b/innobase/btr/ts/trash/tsbtrold5.c new file mode 100644 index 00000000000..370cf0b14bd --- /dev/null +++ b/innobase/btr/ts/trash/tsbtrold5.c @@ -0,0 +1,798 @@ +/************************************************************************ +The test for the index tree + +(c) 1994-1996 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "sync0sync.h" +#include "ut0mem.h" +#include "mem0mem.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "os0file.h" +#include "fil0fil.h" +#include "fsp0fsp.h" +#include "rem0rec.h" +#include "rem0cmp.h" +#include "mtr0mtr.h" +#include "log0log.h" +#include "page0page.h" +#include "page0cur.h" +#include "..\btr0btr.h" +#include "..\btr0cur.h" +#include "..\btr0pcur.h" + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[10]; + +mutex_t incs_mutex; +ulint incs; + +byte bigbuf[1000000]; + +#define N_SPACES 1 +#define N_FILES 2 +#define FILE_SIZE 1000 /* must be > 512 */ +#define POOL_SIZE 1000 +#define COUNTER_OFFSET 1500 + +#define LOOP_SIZE 150 +#define N_THREADS 5 + + +ulint zero = 0; + +buf_block_t* bl_arr[POOL_SIZE]; + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + void* mess; + ulint i; + bool ret; + + segment = *((ulint*)arg); + + printf("Io handler thread %lu starts\n", segment); + + for (i = 0;; i++) { + ret = fil_aio_wait(segment, &mess); + ut_a(ret); + + buf_page_io_complete((buf_block_t*)mess); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + + } + + return(0); +} + +/************************************************************************* +Creates the files for the file system test and inserts them to +the file system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k; + char name[20]; + os_thread_t thr[5]; + os_thread_id_t id[5]; + + printf("--------------------------------------------------------\n"); + printf("Create or open database files\n"); + + strcpy(name, "j:\\tsfile00"); + + for (k = 0; k < N_SPACES; k++) { + for (i = 0; i < N_FILES; i++) { + + name[9] = (char)((ulint)'0' + k); + name[10] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, + OS_FILE_TABLESPACE, &ret); + + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, + OS_FILE_TABLESPACE, &ret); + + ut_a(ret); + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k, OS_FILE_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create(name, FILE_SIZE, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + + for (i = 0; i < 5; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/************************************************************************ +Inits space header of space 0. */ + +void +init_space(void) +/*============*/ +{ + mtr_t mtr; + + printf("Init space header\n"); + + mtr_start(&mtr); + + fsp_header_init(0, FILE_SIZE * N_FILES, &mtr); + + mtr_commit(&mtr); +} + +/********************************************************************* +Test for index page. */ + +void +test1(void) +/*=======*/ +{ + dtuple_t* tuple; + mem_heap_t* heap; + ulint rnd = 0; + dict_index_t* index; + dict_table_t* table; + dict_tree_t* tree; + mtr_t mtr; + byte buf[8]; + ulint i; + ulint tm, oldtm; + btr_pcur_t cursor; + + printf("-------------------------------------------------\n"); + printf("TEST 1. Basic test\n"); + + heap = mem_heap_create(0); + + table = dict_mem_table_create("TS_TABLE1", 2); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, DATA_ENGLISH, 10, 0); + + dict_table_add_to_cache(table); + + index = dict_mem_index_create("TS_TABLE1", "IND1", 0, 2, 0); + + dict_mem_index_add_field(index, "COL1", 0); + dict_mem_index_add_field(index, "COL2", 0); + + dict_index_add_to_cache(index); + + index = dict_index_get("TS_TABLE1", "IND1"); + ut_a(index); + + tree = dict_index_get_tree(index); + + tuple = dtuple_create(heap, 3); + + mtr_start(&mtr); + + btr_root_create(tree, 0, &mtr); + + mtr_commit(&mtr); + + mtr_start(&mtr); + + dtuple_gen_test_tuple3(tuple, 0, buf); + btr_insert(tree, tuple, &mtr); + + mtr_commit(&mtr); + + rnd = 90000; + + oldtm = ut_clock(); + + for (i = 0; i < 1000 * UNIV_DBC * UNIV_DBC; i++) { + + mtr_start(&mtr); + + if (i == 77000) { + rnd = rnd % 200000; + } + + rnd = (rnd + 15675751) % 200000; + + dtuple_gen_test_tuple3(tuple, rnd, buf); + + btr_insert(tree, tuple, &mtr); + + mtr_commit(&mtr); + } + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + + rnd = 90000; + + oldtm = ut_clock(); + + for (i = 0; i < 1000 * UNIV_DBC * UNIV_DBC; i++) { + + mtr_start(&mtr); + + if (i == 50000) { + rnd = rnd % 200000; + } + + rnd = (rnd + 595659561) % 200000; + + dtuple_gen_test_tuple3(tuple, rnd, buf); + + btr_pcur_open(tree, tuple, PAGE_CUR_GE, + BTR_SEARCH_LEAF, &cursor, &mtr); + + mtr_commit(&mtr); + } + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 1000 * UNIV_DBC * UNIV_DBC; i++) { + + mtr_start(&mtr); + + rnd = (rnd + 35608971) % 200000 + 1; + + dtuple_gen_test_tuple3(tuple, rnd, buf); + + mtr_commit(&mtr); + } + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + +/* btr_print_tree(tree, 3); */ + + mem_heap_free(heap); +} + + +#ifdef notdefined + + mtr_start(&mtr); + + block = buf_page_create(0, 5, &mtr); + buf_page_x_lock(block, &mtr); + + frame = buf_block_get_frame(block); + + page = page_create(frame, &mtr); + + for (i = 0; i < 512; i++) { + + rnd = (rnd + 534671) % 512; + + if (i % 27 == 0) { + ut_a(page_validate(page, index)); + } + + dtuple_gen_test_tuple(tuple, rnd); + +/* dtuple_print(tuple);*/ + + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + rec = page_cur_insert_rec(&cursor, tuple, NULL, &mtr); + + ut_a(rec); + + rec_validate(rec); +/* page_print_list(page, 151); */ + } + +/* page_print_list(page, 151); */ + + ut_a(page_validate(page, index)); + ut_a(page_get_n_recs(page) == 512); + + for (i = 0; i < 512; i++) { + + rnd = (rnd + 7771) % 512; + + if (i % 27 == 0) { + ut_a(page_validate(page, index)); + } + + dtuple_gen_test_tuple(tuple, rnd); + +/* dtuple_print(tuple);*/ + + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + page_cur_delete_rec(&cursor, &mtr); + + ut_a(rec); + + rec_validate(rec); +/* page_print_list(page, 151); */ + } + + ut_a(page_get_n_recs(page) == 0); + + ut_a(page_validate(page, index)); + page = page_create(frame, &mtr); + + rnd = 311; + + for (i = 0; i < 512; i++) { + + rnd = (rnd + 1) % 512; + + if (i % 27 == 0) { + ut_a(page_validate(page, index)); + } + + dtuple_gen_test_tuple(tuple, rnd); + +/* dtuple_print(tuple);*/ + + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + rec = page_cur_insert_rec(&cursor, tuple, NULL, &mtr); + + ut_a(rec); + + rec_validate(rec); +/* page_print_list(page, 151); */ + } + + ut_a(page_validate(page, index)); + ut_a(page_get_n_recs(page) == 512); + + rnd = 217; + + for (i = 0; i < 512; i++) { + + rnd = (rnd + 1) % 512; + + if (i % 27 == 0) { + ut_a(page_validate(page, index)); + } + + dtuple_gen_test_tuple(tuple, rnd); + +/* dtuple_print(tuple);*/ + + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + page_cur_delete_rec(&cursor, &mtr); + + ut_a(rec); + + rec_validate(rec); +/* page_print_list(page, 151); */ + } + + ut_a(page_validate(page, index)); + ut_a(page_get_n_recs(page) == 0); + page = page_create(frame, &mtr); + + rnd = 291; + + for (i = 0; i < 512; i++) { + + rnd = (rnd - 1) % 512; + + if (i % 27 == 0) { + ut_a(page_validate(page, index)); + } + + dtuple_gen_test_tuple(tuple, rnd); + +/* dtuple_print(tuple);*/ + + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + rec = page_cur_insert_rec(&cursor, tuple, NULL, &mtr); + + ut_a(rec); + + rec_validate(rec); +/* page_print_list(page, 151); */ + } + + ut_a(page_validate(page, index)); + ut_a(page_get_n_recs(page) == 512); + + rnd = 277; + + for (i = 0; i < 512; i++) { + + rnd = (rnd - 1) % 512; + + if (i % 27 == 0) { + ut_a(page_validate(page, index)); + } + + dtuple_gen_test_tuple(tuple, rnd); + +/* dtuple_print(tuple);*/ + + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + page_cur_delete_rec(&cursor, &mtr); + + ut_a(rec); + + rec_validate(rec); +/* page_print_list(page, 151); */ + } + + ut_a(page_validate(page, index)); + ut_a(page_get_n_recs(page) == 0); + + mtr_commit(&mtr); + mem_heap_free(heap); +} + +/********************************************************************* +Test for index page. */ + +void +test2(void) +/*=======*/ +{ + page_t* page; + dtuple_t* tuple; + mem_heap_t* heap; + ulint i, j; + ulint rnd = 0; + rec_t* rec; + page_cur_t cursor; + dict_index_t* index; + dict_table_t* table; + buf_block_t* block; + buf_frame_t* frame; + ulint tm, oldtm; + byte buf[8]; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2. Speed test\n"); + + oldtm = ut_clock(); + + for (i = 0; i < 1000 * UNIV_DBC * UNIV_DBC; i++) { + ut_memcpy(bigbuf, bigbuf + 800, 800); + } + + tm = ut_clock(); + printf("Wall time for %lu mem copys of 800 bytes %lu millisecs\n", + i, tm - oldtm); + + oldtm = ut_clock(); + + rnd = 0; + for (i = 0; i < 1000 * UNIV_DBC * UNIV_DBC; i++) { + ut_memcpy(bigbuf + rnd, bigbuf + rnd + 800, 800); + rnd += 1600; + if (rnd > 995000) { + rnd = 0; + } + } + + tm = ut_clock(); + printf("Wall time for %lu mem copys of 800 bytes %lu millisecs\n", + i, tm - oldtm); + + heap = mem_heap_create(0); + + table = dict_table_create("TS_TABLE2", 2); + + dict_table_add_col(table, "COL1", DATA_VARCHAR, DATA_ENGLISH, 10, 0); + dict_table_add_col(table, "COL2", DATA_VARCHAR, DATA_ENGLISH, 10, 0); + + ut_a(0 == dict_table_publish(table)); + + index = dict_index_create("TS_TABLE2", "IND2", 0, 2, 0); + + dict_index_add_field(index, "COL1", 0); + dict_index_add_field(index, "COL2", 0); + + ut_a(0 == dict_index_publish(index)); + + index = dict_index_get("TS_TABLE2", "IND2"); + ut_a(index); + + tuple = dtuple_create(heap, 2); + + oldtm = ut_clock(); + + rnd = 677; + for (i = 0; i < 4 * UNIV_DBC * UNIV_DBC; i++) { + + mtr_start(&mtr); + + block = buf_page_create(0, 5, &mtr); + buf_page_x_lock(block, &mtr); + + frame = buf_block_get_frame(block); + + page = page_create(frame, &mtr); + + for (j = 0; j < 250; j++) { + rnd = (rnd + 54841) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + rec = page_cur_insert_rec(&cursor, tuple, NULL, &mtr); + ut_a(rec); + } + mtr_commit(&mtr); + } + + tm = ut_clock(); + printf("Wall time for insertion of %lu recs %lu milliseconds\n", + i * j, tm - oldtm); + + mtr_start(&mtr); + + block = buf_page_get(0, 5, &mtr); + buf_page_s_lock(block, &mtr); + + page = buf_block_get_frame(block); + ut_a(page_validate(page, index)); + mtr_commit(&mtr); + + oldtm = ut_clock(); + + rnd = 677; + for (i = 0; i < 4 * UNIV_DBC * UNIV_DBC; i++) { + mtr_start(&mtr); + + block = buf_page_create(0, 5, &mtr); + buf_page_x_lock(block, &mtr); + + frame = buf_block_get_frame(block); + + page = page_create(frame, &mtr); + + for (j = 0; j < 250; j++) { + rnd = (rnd + 54841) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + } + mtr_commit(&mtr); + } + + tm = ut_clock(); + printf( + "Wall time for %lu empty loops with page create %lu milliseconds\n", + i * j, tm - oldtm); + + oldtm = ut_clock(); + + for (i = 0; i < 4 * UNIV_DBC * UNIV_DBC; i++) { + + mtr_start(&mtr); + + block = buf_page_create(0, 5, &mtr); + buf_page_x_lock(block, &mtr); + + frame = buf_block_get_frame(block); + + page = page_create(frame, &mtr); + + rnd = 100; + for (j = 0; j < 250; j++) { + rnd = (rnd + 1) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + rec = page_cur_insert_rec(&cursor, tuple, NULL, &mtr); + ut_a(rec); + } + mtr_commit(&mtr); + } + + tm = ut_clock(); + printf( + "Wall time for sequential insertion of %lu recs %lu milliseconds\n", + i * j, tm - oldtm); + + + oldtm = ut_clock(); + + for (i = 0; i < 4 * UNIV_DBC * UNIV_DBC; i++) { + mtr_start(&mtr); + + block = buf_page_create(0, 5, &mtr); + buf_page_x_lock(block, &mtr); + + frame = buf_block_get_frame(block); + + page = page_create(frame, &mtr); + + rnd = 500; + for (j = 0; j < 250; j++) { + rnd = (rnd - 1) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + rec = page_cur_insert_rec(&cursor, tuple, NULL, &mtr); + ut_a(rec); + } + mtr_commit(&mtr); + } + + tm = ut_clock(); + printf( + "Wall time for descend. seq. insertion of %lu recs %lu milliseconds\n", + i * j, tm - oldtm); + + oldtm = ut_clock(); + + for (i = 0; i < 4 * UNIV_DBC * UNIV_DBC; i++) { + mtr_start(&mtr); + + block = buf_page_create(0, 5, &mtr); + buf_page_x_lock(block, &mtr); + + frame = buf_block_get_frame(block); + + page = page_create(frame, &mtr); + + rnd = 677; + + for (j = 0; j < 250; j++) { + rnd = (rnd + 54841) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + rec = page_cur_insert_rec(&cursor, tuple, NULL, &mtr); + ut_a(rec); + } + + rnd = 677; + for (j = 0; j < 250; j++) { + rnd = (rnd + 54841) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + page_cur_delete_rec(&cursor, &mtr); + } + ut_a(page_get_n_recs(page) == 0); + + mtr_commit(&mtr); + } + + tm = ut_clock(); + printf("Wall time for insert and delete of %lu recs %lu milliseconds\n", + i * j, tm - oldtm); + + mtr_start(&mtr); + + block = buf_page_create(0, 5, &mtr); + buf_page_x_lock(block, &mtr); + + frame = buf_block_get_frame(block); + + page = page_create(frame, &mtr); + + rnd = 677; + + for (j = 0; j < 250; j++) { + rnd = (rnd + 54841) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + + rec = page_cur_insert_rec(&cursor, tuple, NULL, &mtr); + ut_a(rec); + } + ut_a(page_validate(page, index)); + mtr_print(&mtr); + + oldtm = ut_clock(); + + for (i = 0; i < 4 * UNIV_DBC * UNIV_DBC; i++) { + rnd = 677; + for (j = 0; j < 250; j++) { + rnd = (rnd + 54841) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + page_cur_search(page, tuple, PAGE_CUR_G, &cursor); + } + } + + tm = ut_clock(); + printf("Wall time for search of %lu recs %lu milliseconds\n", + i * j, tm - oldtm); + + oldtm = ut_clock(); + + for (i = 0; i < 4 * UNIV_DBC * UNIV_DBC; i++) { + rnd = 677; + for (j = 0; j < 250; j++) { + rnd = (rnd + 54841) % 1000; + dtuple_gen_test_tuple2(tuple, rnd, buf); + } + } + + tm = ut_clock(); + printf("Wall time for %lu empty loops %lu milliseconds\n", + i * j, tm - oldtm); + mtr_commit(&mtr); +} + +#endif + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + + sync_init(); + mem_init(); + os_aio_init(160, 5); + fil_init(25); + buf_pool_init(POOL_SIZE, POOL_SIZE); + dict_init(); + fsp_init(); + log_init(); + + create_files(); + + init_space(); + + oldtm = ut_clock(); + + ut_rnd_set_seed(19); + + test1(); + +/* mem_print_info(); */ + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/btr/ts/trash/tscli.c b/innobase/btr/ts/trash/tscli.c new file mode 100644 index 00000000000..622da894e02 --- /dev/null +++ b/innobase/btr/ts/trash/tscli.c @@ -0,0 +1,2263 @@ +/************************************************************************ +Test for the client + +(c) 1996-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "ib_odbc.h" + +/********************************************************************* +Test for TPC-C. */ + +ulint +test_c( +/*===*/ + void* arg) +{ + HSTMT* query; + HSTMT* commit_query; + HSTMT* new_order_query; + HSTMT* payment_query; + HSTMT* order_status_query; + HSTMT* delivery_query; + HSTMT* stock_level_query; + HSTMT* print_query; + ulint tm, oldtm; + char* str; + char* str1; + char* str2; + char* str3; + char* str4; + char* str5; + char* str6; + ulint i; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST. CREATE TABLES FOR TPC-C\n"); + + /*------------------------------------------------------*/ + + str1 = + +" PROCEDURE CREATE_TABLES () IS" +" BEGIN" +" CREATE TABLE WAREHOUSE (W_ID CHAR, W_NAME CHAR," +" W_STREET_1 CHAR, W_STREET_2 CHAR," +" W_CITY CHAR," +" W_STATE CHAR, W_ZIP CHAR," +" W_TAX INT," +" W_YTD_HIGH INT," +" W_YTD INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX W_IND ON WAREHOUSE (W_ID);" +"" +" CREATE TABLE DISTRICT (D_ID CHAR, D_W_ID CHAR," +" D_NAME CHAR," +" D_STREET_1 CHAR, D_STREET_2 CHAR," +" D_CITY CHAR," +" D_STATE CHAR, D_ZIP CHAR," +" D_TAX INT," +" D_YTD_HIGH INT," +" D_YTD INT," +" D_NEXT_O_ID INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX D_IND ON DISTRICT (D_W_ID, D_ID);" +"" +" CREATE TABLE CUSTOMER (C_ID CHAR, C_D_ID CHAR, C_W_ID CHAR," +" C_FIRST CHAR, C_MIDDLE CHAR," +" C_LAST CHAR," +" C_STREET_1 CHAR, C_STREET_2 CHAR," +" C_CITY CHAR," +" C_STATE CHAR, C_ZIP CHAR," +" C_PHONE CHAR," +" C_SINCE_TIME INT," +" C_SINCE INT," +" C_CREDIT CHAR," +" C_CREDIT_LIM_HIGH INT," +" C_CREDIT_LIM INT," +" C_DISCOUNT INT," +" C_BALANCE_HIGH INT," +" C_BALANCE INT," +" C_YTD_PAYMENT_HIGH INT," +" C_YTD_PAYMENT INT," +" C_PAYMENT_CNT INT," +" C_DELIVERY_CNT INT," +" C_DATA CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX C_IND ON CUSTOMER (C_W_ID, C_D_ID," +" C_ID);" +"" +" CREATE INDEX C_LAST_IND ON CUSTOMER (C_W_ID, C_D_ID, C_LAST," +" C_FIRST);" +"" +" CREATE TABLE HISTORY (H_C_ID CHAR, H_C_D_ID CHAR, H_C_W_ID CHAR," +" H_D_ID CHAR, H_W_ID CHAR," +" H_DATE INT," +" H_AMOUNT INT," +" H_DATA CHAR);" +"" +" CREATE CLUSTERED INDEX H_IND ON HISTORY (H_W_ID);" +"" +" CREATE TABLE NEW_ORDER (NO_O_ID INT," +" NO_D_ID CHAR," +" NO_W_ID CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX NO_IND ON NEW_ORDER (NO_W_ID, NO_D_ID," +" NO_O_ID);" + ; + + str2 = + +" CREATE TABLE ORDERS (O_ID INT, O_D_ID CHAR, O_W_ID CHAR," +" O_C_ID CHAR," +" O_ENTRY_D INT," +" O_CARRIER_ID INT," +" O_OL_CNT INT," +" O_ALL_LOCAL CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX O_IND ON ORDERS (O_W_ID, O_D_ID," +" O_ID);" +" CREATE INDEX O_C_IND ON ORDERS (O_W_ID, O_D_ID, O_C_ID);" +"" +" CREATE TABLE ORDER_LINE (OL_O_ID INT, OL_D_ID CHAR, OL_W_ID CHAR," +" OL_NUMBER CHAR," +" OL_I_ID CHAR," +" OL_SUPPLY_W_ID CHAR," +" OL_DELIVERY_D INT," +" OL_QUANTITY INT," +" OL_AMOUNT INT," +" OL_DIST_INFO CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX OL_IND ON ORDER_LINE" +" (OL_W_ID, OL_D_ID, OL_O_ID, OL_NUMBER);" +"" +" CREATE TABLE ITEM (I_ID CHAR, I_IM_ID CHAR, I_NAME CHAR," +" I_PRICE INT," +" I_DATA CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX I_IND ON ITEM (I_ID);" +"" +" CREATE TABLE STOCK (S_I_ID CHAR," +" S_W_ID CHAR," +" S_QUANTITY INT," +" S_DIST_01 CHAR," +" S_DIST_02 CHAR," +" S_DIST_03 CHAR," +" S_DIST_04 CHAR," +" S_DIST_05 CHAR," +" S_DIST_06 CHAR," +" S_DIST_07 CHAR," +" S_DIST_08 CHAR," +" S_DIST_09 CHAR," +" S_DIST_10 CHAR," +" S_YTD INT," +" S_ORDER_CNT INT," +" S_REMOTE_CNT INT," +" S_DATA CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX S_IND ON STOCK (S_W_ID, S_I_ID);" +" END;" + ; + + str = ut_str_catenate(str1, str2); + + query = pars_sql(str); + + mem_free(str); + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + + /*-----------------------------------------------------------*/ + printf("\n\nPopulate TPC-C tables\n\n"); + + str1 = + +" PROCEDURE POPULATE_TABLES () IS" +"" +" i INT;" +" j INT;" +" k INT;" +" t INT;" +" string CHAR;" +" rnd1 INT;" +" rnd2 INT;" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +"" +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 200;" +"" +" PRINTF('Starting to populate ITEMs');" +"" +" FOR i IN 1 .. n_items LOOP" +" rnd1 := RND(26, 50);" +" string := RND_STR(rnd1);" +"" +" IF (RND(0, 9) = 0) THEN" +" rnd2 := RND(0, rnd1 - 8);" +" REPLSTR(string, 'ORIGINAL', rnd2, 8);" +" COMMIT WORK;" +" END IF;" +"" +" INSERT INTO ITEM VALUES (TO_BINARY(i, 3)," +" TO_BINARY(RND(1, 10000), 3)," +" RND_STR(RND(14, 24))," +" RND(100, 10000)," +" string);" +" END LOOP;" +"" +" FOR i IN 1 .. n_warehouses LOOP" +" PRINTF('Starting to populate warehouse number ', i);" +" INSERT INTO WAREHOUSE VALUES (TO_BINARY(i, 2)," +" RND_STR(RND(6, 10))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(2)," +" CONCAT(SUBSTR(TO_CHAR(RND(0, 9999))," +" 6, 4)," +" '11111')," +" RND(0, 2000)," +" 0," +" 0);" +" FOR j IN 1 .. n_items LOOP" +"" +" rnd1 := RND(26, 50);" +" string := RND_STR(rnd1);" +"" +" IF (RND(0, 9) = 0) THEN" +" rnd2 := RND(0, rnd1 - 8);" +" REPLSTR(string, 'ORIGINAL', rnd2, 8);" +" COMMIT WORK;" +" END IF; " +"" +" INSERT INTO STOCK VALUES (TO_BINARY(j, 3)," +" TO_BINARY(i, 2)," +" RND(10, 100)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" 0, 0, 0," +" string);" +" END LOOP;" + ; + + str2 = +" FOR j IN 1 .. n_districts LOOP" +"" +" COMMIT WORK;" +" PRINTF('Starting to populate district number ', j);" +" INSERT INTO DISTRICT VALUES (TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" RND_STR(RND(6, 10))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(2)," +" CONCAT(SUBSTR(" +" TO_CHAR(RND(0, 9999))," +" 6, 4)," +" '11111')," +" RND(0, 2000)," +" 0," +" 0," +" 3001);" +"" +" FOR k IN 1 .. n_customers LOOP" +"" +" string := 'GC';" +"" +" IF (RND(0, 9) = 7) THEN" +" COMMIT WORK;" +" string := 'BC';" +" END IF;" +" " +" INSERT INTO CUSTOMER VALUES (" +" TO_BINARY(k, 3)," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" RND_STR(RND(8, 16))," +" 'OE'," +" CONCAT('NAME'," +" TO_CHAR(k / 3))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(2)," +" CONCAT(SUBSTR(" +" TO_CHAR(RND(0, 9999))," +" 6, 4)," +" '11111')," +" RND_STR(16)," +" SYSDATE(), 0," +" string," +" 0, 5000000," +" RND(0, 5000)," +" 0, 0, 0, 0, 0, 0," +" RND_STR(RND(300, 500)));" + ; + + str3 = +" INSERT INTO HISTORY VALUES (" +" TO_BINARY(k, 3)," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" SYSDATE()," +" 1000," +" RND_STR(RND(12, 24)));" +"" +" rnd1 := RND(5, 15);" +"" +" INSERT INTO ORDERS VALUES (" +" k," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" TO_BINARY(k, 3)," +" SYSDATE()," +" RND(1, 10)," +" rnd1," +" '1');" +"" +" FOR t IN 1 .. rnd1 LOOP" +" INSERT INTO ORDER_LINE VALUES (" +" k," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" TO_BINARY(t, 1)," +" TO_BINARY(" +" RND(0, n_items - 1)," +" 3)," +" TO_BINARY(i, 2)," +" SYSDATE()," +" RND(0, 99)," +" RND(0, 9999)," +" RND_STR(24));" +" END LOOP;" +" END LOOP;" +" " +" FOR k IN (2 * n_customers) / 3 .. n_customers LOOP" +" " +" INSERT INTO NEW_ORDER VALUES (" +" k," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2));" +" END LOOP;" +" END LOOP;" +" END LOOP; " +" " +" COMMIT WORK;" +" END;" + ; + + str4 = ut_str_catenate(str1, str2); + str = ut_str_catenate(str4, str3); + + query = pars_sql(str); + + mem_free(str); + mem_free(str4); + + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE PRINT_TABLES () IS" +" BEGIN" +"" +" /* PRINTF('Printing ITEM table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM ITEM;" +"" +" PRINTF('Printing WAREHOUSE table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM WAREHOUSE;" +"" +" PRINTF('Printing STOCK table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM STOCK;" +"" +" PRINTF('Printing DISTRICT table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM DISTRICT;" +"" +" PRINTF('Printing CUSTOMER table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM CUSTOMER;" +"" +" PRINTF('Printing HISTORY table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM HISTORY;" +"" +" PRINTF('Printing ORDERS table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM ORDERS;" +"" +" PRINTF('Printing ORDER_LINE table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM ORDER_LINE" +" WHERE OL_O_ID >= 3000; */" +"" +" PRINTF('Printing NEW_ORDER table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM NEW_ORDER;" +"" +" COMMIT WORK;" +" END;" + ; + + print_query = pars_sql(str); + + /*-----------------------------------------------------------*/ + commit_query = pars_sql( + +" PROCEDURE COMMIT_TEST () IS" +" " +" BEGIN" +" COMMIT WORK;" +" END;" + ); + + + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE NEW_ORDER () IS" +"" +" i INT;" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" w_tax INT;" +" c_w_id CHAR;" +" c_d_id CHAR;" +" c_id CHAR;" +" c_discount INT;" +" c_last CHAR;" +" c_credit CHAR;" +" d_tax INT;" +" o_id INT;" +" o_ol_cnt INT;" +" ol_i_id CHAR;" +" o_entry_d INT;" +" o_all_local CHAR;" +" i_price INT;" +" i_name CHAR;" +" i_data CHAR;" +" s_quantity INT;" +" s_data CHAR;" +" s_dist_01 CHAR;" +" s_dist_02 CHAR;" +" s_dist_03 CHAR;" +" s_dist_04 CHAR;" +" s_dist_05 CHAR;" +" s_dist_06 CHAR;" +" s_dist_07 CHAR;" +" s_dist_08 CHAR;" +" s_dist_09 CHAR;" +" s_dist_10 CHAR;" +" bg CHAR;" +" ol_quantity INT;" +" ol_amount INT;" +" ol_supply_w_id CHAR;" +" ol_dist_info CHAR;" +" total INT;" +"" +" DECLARE CURSOR district_cursor IS" +" SELECT D_NEXT_O_ID, D_TAX" +" FROM DISTRICT" +" WHERE D_ID = c_d_id AND D_W_ID = c_w_id" +" FOR UPDATE;" +"" +" DECLARE CURSOR stock_cursor IS" +" SELECT S_QUANTITY, S_DATA," +" S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04," +" S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08," +" S_DIST_09, S_DIST_10" +" FROM STOCK" +" WHERE S_W_ID = ol_supply_w_id AND S_I_ID = ol_i_id" +" FOR UPDATE;" + ; + str2 = + +" BEGIN" +" " +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 200;" +" " +" c_w_id := TO_BINARY(RND(1, n_warehouses), 2);" +" c_d_id := TO_BINARY(RND(1, n_districts) + 47, 1);" +" c_id := TO_BINARY(RND(1, n_customers), 3);" +"" +" o_ol_cnt := RND(5, 15);" +" o_all_local := '1';" +" bg := 'GGGGGGGGGGGGGGG';" +" total := 0;" +" " +" SELECT W_TAX INTO w_tax" +" FROM WAREHOUSE" +" WHERE W_ID = c_w_id;" +"" +" OPEN district_cursor;" +"" +" FETCH district_cursor INTO o_id, d_tax;" +"" +" /* PRINTF('C-warehouse id ', BINARY_TO_NUMBER(c_w_id)," +" ' C-district id ', c_d_id," +" ' order id ', o_id, ' linecount ', o_ol_cnt); */" +"" +" UPDATE DISTRICT SET D_NEXT_O_ID = o_id + 1" +" WHERE CURRENT OF district_cursor;" +"" +" CLOSE district_cursor;" +"" +" SELECT C_DISCOUNT, C_LAST, C_CREDIT INTO c_discount, c_last, c_credit" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id AND C_ID = c_id;" +"" + ; + str3 = + +" FOR i IN 1 .. o_ol_cnt LOOP" +"" +" ol_i_id := TO_BINARY(RND(1, n_items), 3);" +"" +" ol_supply_w_id := c_w_id;" +"" +" ol_quantity := RND(1, 10);" +"" +" SELECT I_PRICE, I_NAME, I_DATA INTO i_price, i_name, i_data" +" FROM ITEM" +" WHERE I_ID = ol_i_id;" +"" +" IF (SQL % NOTFOUND) THEN" +" PRINTF('Rolling back');" +" ROLLBACK WORK;" +"" +" RETURN;" +" END IF;" +"" +" OPEN stock_cursor;" +"" +" FETCH stock_cursor INTO s_quantity, s_data," +" s_dist_01, s_dist_02, s_dist_03," +" s_dist_04, s_dist_05, s_dist_06," +" s_dist_07, s_dist_08, s_dist_09," +" s_dist_10;" +"" +" IF (s_quantity >= ol_quantity + 10) THEN" +" s_quantity := s_quantity - ol_quantity;" +" ELSE" +" s_quantity := (s_quantity + 91) - ol_quantity;" +" END IF;" +"" +" UPDATE STOCK SET S_QUANTITY = s_quantity," +" S_YTD = S_YTD + ol_quantity," +" S_ORDER_CNT = S_ORDER_CNT + 1" +" WHERE CURRENT OF stock_cursor;" +"" +" IF (ol_supply_w_id <> c_w_id) THEN" +"" +" o_all_local := '0';" +" PRINTF('Remote order '," +" BINARY_TO_NUMBER(ol_supply_w_id), ' '," +" BINARY_TO_NUMBER(c_w_id));" +"" +" UPDATE STOCK SET S_REMOTE_CNT = S_REMOTE_CNT + 1" +" WHERE CURRENT OF stock_cursor;" +" END IF;" +"" +" CLOSE stock_cursor;" +"" +" IF ((INSTR(i_data, 'ORIGINAL') > 0)" +" OR (INSTR(s_data, 'ORIGINAL') > 0)) THEN" +" REPLSTR(bg, 'B', i - 1, 1);" +" END IF;" +"" +" ol_amount := ol_quantity * i_price;" +"" +" total := total + ol_amount;" + ; + str4 = +" IF (c_d_id = '0') THEN" +" ol_dist_info := s_dist_01;" +" ELSIF (c_d_id = '1') THEN" +" ol_dist_info := s_dist_02;" +" ELSIF (c_d_id = '2') THEN" +" ol_dist_info := s_dist_03;" +" ELSIF (c_d_id = '3') THEN" +" ol_dist_info := s_dist_04;" +" ELSIF (c_d_id = '4') THEN" +" ol_dist_info := s_dist_05;" +" ELSIF (c_d_id = '5') THEN" +" ol_dist_info := s_dist_06;" +" ELSIF (c_d_id = '6') THEN" +" ol_dist_info := s_dist_07;" +" ELSIF (c_d_id = '7') THEN" +" ol_dist_info := s_dist_08;" +" ELSIF (c_d_id = '8') THEN" +" ol_dist_info := s_dist_09;" +" ELSIF (c_d_id = '9') THEN" +" ol_dist_info := s_dist_10;" +" END IF;" +"" +" INSERT INTO ORDER_LINE VALUES (o_id, c_d_id, c_w_id," +" TO_BINARY(i, 1), ol_i_id," +" ol_supply_w_id, NULL, ol_quantity," +" ol_amount, ol_dist_info); " +" END LOOP;" +"" +" total := (((total * (10000 + w_tax + d_tax)) / 10000)" +" * (10000 - c_discount)) / 10000;" +"" +" o_entry_d := SYSDATE();" +"" +" INSERT INTO ORDERS VALUES (o_id, c_d_id, c_w_id, c_id, o_entry_d," +" NULL, o_ol_cnt, o_all_local);" +" INSERT INTO NEW_ORDER VALUES (o_id, c_d_id, c_w_id);" +"" +" /* PRINTF('Inserted order lines:');" +" ROW_PRINTF" +" SELECT * FROM ORDER_LINE WHERE OL_O_ID = o_id AND" +" OL_D_ID = c_d_id" +" AND OL_W_ID = c_w_id; */" +" /* COMMIT WORK; */" +" END;" + ; + + str5 = ut_str_catenate(str1, str2); + str6 = ut_str_catenate(str3, str4); + + str = ut_str_catenate(str5, str6); + + new_order_query = pars_sql(str); + + mem_free(str); + mem_free(str5); + mem_free(str6); + + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE PAYMENT () IS" +"" +" i INT;" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" w_id CHAR;" +" w_street_1 CHAR;" +" w_street_2 CHAR;" +" w_city CHAR;" +" w_state CHAR;" +" w_zip CHAR;" +" w_name CHAR;" +" d_id CHAR;" +" d_street_1 CHAR;" +" d_street_2 CHAR;" +" d_city CHAR;" +" d_state CHAR;" +" d_zip CHAR;" +" d_name CHAR;" +" c_w_id CHAR;" +" c_d_id CHAR;" +" c_street_1 CHAR;" +" c_street_2 CHAR;" +" c_city CHAR;" +" c_state CHAR;" +" c_zip CHAR;" +" c_id CHAR;" +" c_last CHAR;" +" c_first CHAR;" +" c_middle CHAR;" +" c_phone CHAR;" +" c_credit CHAR;" +" c_credit_lim INT;" +" c_discount INT;" +" c_balance INT;" +" c_since INT;" +" c_data CHAR;" +" byname INT;" +" namecnt INT;" +" amount INT;" +" h_data CHAR;" +" h_date INT;" +" c_more_data CHAR;" +" more_len INT;" +" data_len INT;" +"" +" DECLARE CURSOR warehouse_cursor IS" +" SELECT W_STREET_1, W_STREET_2, W_CITY, W_STATE, W_ZIP, W_NAME" +" FROM WAREHOUSE" +" WHERE W_ID = w_id" +" FOR UPDATE;" +"" +" DECLARE CURSOR district_cursor IS" +" SELECT D_STREET_1, D_STREET_2, D_CITY, D_STATE, D_ZIP, D_NAME" +" FROM DISTRICT" +" WHERE D_W_ID = w_id AND D_ID = d_id" +" FOR UPDATE;" +"" +" DECLARE CURSOR customer_by_name_cursor IS" +" SELECT C_ID" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_LAST = c_last" +" ORDER BY C_FIRST ASC;" +"" +" DECLARE CURSOR customer_cursor IS" +" SELECT C_FIRST, C_MIDDLE, C_LAST, C_STREET_1, C_STREET_2," +" C_CITY, C_STATE, C_ZIP, C_PHONE, C_CREDIT," +" C_CREDIT_LIM, C_DISCOUNT, C_BALANCE," +" C_SINCE" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_ID = c_id" +" FOR UPDATE;" + ; + + str2 = + +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 200;" +"" +" byname := RND(1, 100);" +" amount := RND(1, 1000);" +" h_date := SYSDATE();" +" w_id := TO_BINARY(RND(1, n_warehouses), 2);" +" d_id := TO_BINARY(47 + RND(1, n_districts), 1);" +" c_w_id := TO_BINARY(RND(1, n_warehouses), 2);" +" c_d_id := TO_BINARY(47 + RND(1, n_districts), 1);" +"" +" OPEN warehouse_cursor;" +"" +" FETCH warehouse_cursor INTO w_street_1, w_street_2, w_city, w_state," +" w_zip, w_name;" +" UPDATE WAREHOUSE SET W_YTD = W_YTD + amount" +" WHERE CURRENT OF warehouse_cursor;" +"" +" CLOSE warehouse_cursor;" +"" +" OPEN district_cursor;" +"" +" FETCH district_cursor INTO d_street_1, d_street_2, d_city, d_state," +" d_zip, d_name;" +" UPDATE DISTRICT SET D_YTD = D_YTD + amount" +" WHERE CURRENT OF district_cursor;" +"" +" CLOSE district_cursor;" +"" +" IF (byname <= 60) THEN" +" c_last := CONCAT('NAME', TO_CHAR(RND(1, n_customers) / 3));" +"" +" SELECT COUNT(*) INTO namecnt" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_LAST = c_last;" +" /* PRINTF('Payment trx: Customer name ', c_last," +" ' namecount ', namecnt); */" +" OPEN customer_by_name_cursor;" +"" +" FOR i IN 1 .. (namecnt + 1) / 2 LOOP" +" FETCH customer_by_name_cursor INTO c_id;" +" END LOOP;" +" /* ASSERT(NOT (customer_by_name_cursor % NOTFOUND)); */" +" " +" CLOSE customer_by_name_cursor;" +" ELSE" +" c_id := TO_BINARY(RND(1, n_customers), 3);" +" END IF;" + + ; + str3 = +"" +" /* PRINTF('Payment for customer ', BINARY_TO_NUMBER(c_w_id), ' '," +" c_d_id, ' ', BINARY_TO_NUMBER(c_id)); */" +" OPEN customer_cursor;" +"" +" FETCH customer_cursor INTO c_first, c_middle, c_last, c_street_1," +" c_street_2, c_city, c_state, c_zip," +" c_phone, c_credit, c_credit_lim," +" c_discount, c_balance, c_since;" +" c_balance := c_balance - amount;" +"" +" h_data := CONCAT(w_name, ' ', d_name);" +" " +" IF (c_credit = 'BC') THEN" +" /* PRINTF('Bad customer pays'); */" +"" +" SELECT C_DATA INTO c_data" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_ID = c_id;" +" c_more_data := CONCAT(" +" ' ', TO_CHAR(BINARY_TO_NUMBER(c_id))," +" ' ', c_d_id," +" ' ', TO_CHAR(BINARY_TO_NUMBER(c_w_id))," +" ' ', d_id," +" ' ', TO_CHAR(BINARY_TO_NUMBER(w_id))," +" TO_CHAR(amount)," +" TO_CHAR(h_date)," +" ' ', h_data);" +"" +" more_len := LENGTH(c_more_data);" +" data_len := LENGTH(c_data);" +" " +" IF (more_len + data_len > 500) THEN" +" data_len := 500 - more_len;" +" END IF;" +" " +" c_data := CONCAT(c_more_data, SUBSTR(c_data, 0, data_len));" +" " +" UPDATE CUSTOMER SET C_BALANCE = c_balance," +" C_PAYMENT_CNT = C_PAYMENT_CNT + 1," +" C_YTD_PAYMENT = C_YTD_PAYMENT + amount," +" C_DATA = c_data" +" WHERE CURRENT OF customer_cursor;" +" ELSE" +" UPDATE CUSTOMER SET C_BALANCE = c_balance," +" C_PAYMENT_CNT = C_PAYMENT_CNT + 1," +" C_YTD_PAYMENT = C_YTD_PAYMENT + amount" +" WHERE CURRENT OF customer_cursor;" +" END IF;" +"" +" CLOSE customer_cursor;" +" " +" INSERT INTO HISTORY VALUES (c_d_id, c_w_id, c_id, d_id, w_id," +" h_date, amount, h_data);" +" /* COMMIT WORK; */" +"" +" END;" + + ; + + str4 = ut_str_catenate(str1, str2); + str = ut_str_catenate(str4, str3); + + payment_query = pars_sql(str); + + mem_free(str); + mem_free(str4); + + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE ORDER_STATUS () IS" +"" +" i INT;" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" d_id CHAR;" +" namecnt INT;" +" c_w_id CHAR;" +" c_d_id CHAR;" +" c_id CHAR;" +" c_last CHAR;" +" c_first CHAR;" +" c_middle CHAR;" +" c_balance INT;" +" byname INT;" +" o_id INT;" +" o_carrier_id CHAR;" +" o_entry_d INT;" +" ol_i_id CHAR;" +" ol_supply_w_id CHAR;" +" ol_quantity INT;" +" ol_amount INT;" +" ol_delivery_d INT;" +"" +" DECLARE CURSOR orders_cursor IS" +" SELECT O_ID, O_CARRIER_ID, O_ENTRY_D" +" FROM ORDERS" +" WHERE O_W_ID = c_w_id AND O_D_ID = c_d_id" +" AND O_C_ID = c_id" +" ORDER BY O_ID DESC;" +"" +" DECLARE CURSOR order_line_cursor IS" +" SELECT OL_I_ID, OL_SUPPLY_W_ID, OL_QUANTITY, OL_AMOUNT," +" OL_DELIVERY_D" +" FROM ORDER_LINE" +" WHERE OL_W_ID = c_w_id AND OL_D_ID = c_d_id" +" AND OL_O_ID = o_id;" +" DECLARE CURSOR customer_by_name_cursor IS" +" SELECT C_ID" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_LAST = c_last" +" ORDER BY C_FIRST ASC;" +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 200;" +"" +" c_w_id := TO_BINARY(RND(1, n_warehouses), 2);" +" byname := RND(1, 100);" +"" + ; + + str2 = + +" IF (byname <= 60) THEN" +" d_id := TO_BINARY(47 + RND(1, n_districts), 1); " +"" +" c_d_id := d_id;" +"" +" c_last := CONCAT('NAME', TO_CHAR(RND(1, n_customers) / 3));" +"" +" SELECT COUNT(*) INTO namecnt" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_LAST = c_last;" +" OPEN customer_by_name_cursor;" +"" +" /* PRINTF('Order status trx: Customer name ', c_last," +" ' namecount ', namecnt); */" +" FOR i IN 1 .. (namecnt + 1) / 2 LOOP" +" FETCH customer_by_name_cursor INTO c_id;" +" END LOOP;" +" /* ASSERT(NOT (customer_by_name_cursor % NOTFOUND)); */" +"" +" CLOSE customer_by_name_cursor;" +" ELSE" +" c_d_id := TO_BINARY(47 + RND(1, n_districts), 1);" +" c_id := TO_BINARY(RND(1, n_customers), 3);" +" END IF;" +"" +" SELECT C_BALANCE, C_FIRST, C_MIDDLE, C_LAST INTO c_balance, c_first," +" c_middle, c_last" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id AND C_ID = c_id;" +"" +" OPEN orders_cursor;" +"" +" FETCH orders_cursor INTO o_id, o_carrier_id, o_entry_d;" +"" +" IF (orders_cursor % NOTFOUND) THEN" +" PRINTF('Order status trx: customer has no order');" +" CLOSE orders_cursor;" +"" +" /* COMMIT WORK; */" +"" +" RETURN;" +" END IF;" +"" +" CLOSE orders_cursor;" +"" +" OPEN order_line_cursor;" +"" +" FOR i IN 0 .. 15 LOOP" +" FETCH order_line_cursor INTO ol_i_id, ol_supply_w_id," +" ol_quantity, ol_amount," +" ol_delivery_d;" +"" +" IF (order_line_cursor % NOTFOUND) THEN" +" CLOSE order_line_cursor;" +"" +" /* COMMIT WORK; */" +"" +" RETURN;" +" END IF;" +" END LOOP;" +" ASSERT(0 = 1);" +" " +" END;" + ; + + str = ut_str_catenate(str1, str2); + + order_status_query = pars_sql(str); + + mem_free(str); + + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE DELIVERY () IS" +"" +" i INT;" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" d_id CHAR;" +" w_id CHAR;" +" c_id CHAR;" +" o_id INT;" +" o_carrier_id INT;" +" ol_delivery_d INT;" +" ol_total INT;" +"" +" DECLARE CURSOR new_order_cursor IS" +" SELECT NO_O_ID" +" FROM NEW_ORDER" +" WHERE NO_W_ID = w_id AND NO_D_ID = d_id" +" ORDER BY NO_O_ID ASC;" +"" +" DECLARE CURSOR orders_cursor IS" +" SELECT O_C_ID" +" FROM ORDERS" +" WHERE O_W_ID = w_id AND O_D_ID = d_id" +" AND O_ID = o_id" +" FOR UPDATE;" +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 200;" +"" +" w_id := TO_BINARY(RND(1, n_warehouses), 2);" +" o_carrier_id := RND(1, 10);" +" ol_delivery_d := SYSDATE();" + + ; + + str2 = + +" FOR i IN 1 .. n_districts LOOP" +"" +" d_id := TO_BINARY(47 + i, 1);" +"" +" OPEN new_order_cursor;" +"" +" FETCH new_order_cursor INTO o_id;" +"" +" IF (new_order_cursor % NOTFOUND) THEN" +" /* PRINTF('No order to deliver'); */" +"" +" CLOSE new_order_cursor;" +" ELSE" +" CLOSE new_order_cursor;" +" /* PRINTF('Order to deliver'); */" +"" +" DELETE FROM NEW_ORDER" +" WHERE NO_W_ID = w_id AND NO_D_ID = d_id" +" AND NO_O_ID = o_id;" +" OPEN orders_cursor;" +"" +" FETCH orders_cursor INTO c_id;" +"" +" UPDATE ORDERS SET O_CARRIER_ID = o_carrier_id" +" WHERE CURRENT OF orders_cursor;" +"" +" CLOSE orders_cursor;" +"" +" UPDATE ORDER_LINE SET OL_DELIVERY_D = ol_delivery_d" +" WHERE OL_W_ID = w_id AND OL_D_ID = d_id" +" AND OL_O_ID = o_id;" +"" +" SELECT SUM(OL_AMOUNT) INTO ol_total" +" FROM ORDER_LINE" +" WHERE OL_W_ID = w_id AND OL_D_ID = d_id" +" AND OL_O_ID = o_id;" +"" +" UPDATE CUSTOMER SET C_BALANCE = C_BALANCE - ol_total" +" WHERE C_W_ID = w_id AND C_D_ID = d_id" +" AND C_ID = c_id;" +" END IF;" +" END LOOP;" +"" +" /* COMMIT WORK; */" +" " +" END;" + ; + + str = ut_str_catenate(str1, str2); + + delivery_query = pars_sql(str); + + mem_free(str); + + /*-----------------------------------------------------------*/ + + /* NOTE: COUNT(DISTINCT ...) not implemented yet */ + + str = + +" PROCEDURE STOCK_LEVEL () IS" +"" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" d_id CHAR;" +" w_id CHAR;" +" o_id INT;" +" stock_count INT;" +" threshold INT;" +"" +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 200;" +"" +" w_id := TO_BINARY(RND(1, n_warehouses), 2);" +" d_id := TO_BINARY(47 + 4, 1);" +"" +" threshold := RND(10, 20);" +"" +" SELECT D_NEXT_O_ID INTO o_id" +" FROM DISTRICT" +" WHERE D_W_ID = w_id AND D_ID = d_id;" +"" +" SELECT COUNT(*) INTO stock_count" +" FROM ORDER_LINE, STOCK" +" WHERE OL_W_ID = w_id AND OL_D_ID = d_id" +" AND OL_O_ID >= o_id - 20 AND OL_O_ID < o_id" +" AND S_W_ID = w_id AND S_I_ID = OL_I_ID" +" AND S_QUANTITY < threshold;" +" /* PRINTF(stock_count, ' items under threshold ', threshold); */" +" /* COMMIT WORK; */" +"" +" END;" + ; + + stock_level_query = pars_sql(str); + /*-----------------------------------------------------------*/ + + oldtm = ut_clock(); + + for (i = 0; i < 10; i++) { + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(new_order_query, + SESS_COMM_EXECUTE, 0); + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(payment_query, + SESS_COMM_EXECUTE, 0); + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 10 == 3) { + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(order_status_query, + SESS_COMM_EXECUTE, 0); + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + if ((i % 10 == 6) || (i % 100 == 60)) { + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(delivery_query, + SESS_COMM_EXECUTE, 0); + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + if (i % 10 == 9) { + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(stock_level_query, + SESS_COMM_EXECUTE, 0); + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + if ((i > 0) && (i % 200 == 0)) { + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(commit_query, + SESS_COMM_EXECUTE, 0); + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + } + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + + return(0); +} + +#ifdef notdefined + +/********************************************************************* +General test. */ + +ulint +test1( +/*==*/ + void* arg) +{ + sess_t* sess; + sess_t* sess2; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* query; + que_thr_t* thr; + trx_t* trx; + trx_t* trx2; + ulint tm, oldtm; + ulint j; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1. GENERAL TEST\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + sess2 = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user2", 6); + + trx = sess->trx; + trx2 = sess2->trx; + + mutex_exit(&kernel_mutex); + + /*------------------------------------------------------*/ + query = pars_sql( +" PROCEDURE CREATE_TABLE () IS" +" BEGIN" +" CREATE TABLE TS_TABLE1 (COL1 CHAR, COL2 CHAR, COL3 CHAR);" +" CREATE TABLE TS_TABLE2 (COL21 INT, COL22 INT, COL23 CHAR);" +" CREATE TABLE TS_TABLE3 (COL31 INT, COL32 INT, COL33 CHAR);" +" CREATE TABLE TS_TABLE4 (COL41 INT, COL42 INT, COL43 CHAR);" +" CREATE UNIQUE CLUSTERED INDEX IND1 ON TS_TABLE1 (COL1);" +" CREATE UNIQUE CLUSTERED INDEX IND21 ON TS_TABLE2 (COL21);" +" CREATE UNIQUE CLUSTERED INDEX IND31 ON TS_TABLE3 (COL31);" +" CREATE CLUSTERED INDEX IND41 ON TS_TABLE4 (COL41);" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + + printf("Will start insert test\n"); + + query = pars_sql( + +" PROCEDURE INSERT_SPEED_TEST () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" int2 := 0;" +" int1 := 0;" +" WHILE int1 < 40 LOOP" +" INSERT INTO TS_TABLE2 VALUES (int1, int1 - 100 * (int1 / 100)," +" '123456789012345678901234567890');" +" int1 := int1 + 1;" +" " +" END LOOP;" +" " +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for insert test %lu milliseconds\n", tm - oldtm); + + + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE COMMIT_SPEED_TEST () IS" +" " +" BEGIN" +" COMMIT WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE2"); */ + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + printf("Will start insert test2\n"); + + query = pars_sql( + +" PROCEDURE INSERT_SPEED_TEST2 () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" INSERT INTO TS_TABLE3 SELECT * FROM TS_TABLE2;" +" " +" " +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for insert test2 %lu milliseconds\n", tm - oldtm); + + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE COMMIT_SPEED_TEST () IS" +" " +" BEGIN" +" COMMIT WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE2"); */ + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ +/* os_thread_sleep(1000000); */ + +/* btr_search_table_print_info("TS_TABLE3"); */ + + query = pars_sql( + +" PROCEDURE JOIN_SPEED_TEST () IS" +" int1 INT;" +" " +" BEGIN" +" SELECT COUNT(*) INTO int1" +" FROM TS_TABLE2, TS_TABLE3" +" WHERE COL21 = COL31" +" CONSISTENT READ;" +" PRINTF(int1);" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + for (j = 0; j < 20; j++) { + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, + 0)); + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + + printf("Wall time for join test %lu milliseconds\n", + tm - oldtm); + } + +/* btr_search_table_print_info("TS_TABLE3"); */ + + /*------------------------------------------------------*/ + printf("Will start update test\n"); + + os_thread_sleep(2000000); + + query = pars_sql( + +" PROCEDURE UPDATE_SPEED_TEST () IS" +" int1 INT;" +" BEGIN" +" UPDATE TS_TABLE2 SET COL22 = COL22 + 1;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for update test %lu milliseconds\n", tm - oldtm); + + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE COMMIT_SPEED_TEST () IS" +" " +" BEGIN" +" COMMIT WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE2"); */ + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + printf("Will start TPC-A\n"); + os_thread_sleep(2000000); + + query = pars_sql( +" PROCEDURE TPC_A_SPEED_TEST () IS" +" int1 INT;" +" " +" BEGIN" +" int1 := 0;" +" WHILE int1 < 1000 LOOP" +" INSERT INTO TS_TABLE4 VALUES (int1, int1," +" '123456789012345678901234567890');" +" UPDATE TS_TABLE2 SET COL22 = COL22 + 1" +" WHERE COL21 = int1;" +" UPDATE TS_TABLE2 SET COL22 = COL22 + 1" +" WHERE COL21 = int1 + 1;" +" UPDATE TS_TABLE2 SET COL22 = COL22 + 1" +" WHERE COL21 = int1 + 2;" +" int1 := int1 + 1;" +" END LOOP;" +" " +" END;" + ); + +/*" SELECT COUNT(*) INTO int1 FROM TS_TABLE2 WHERE COL22 = COL21 + 4;" +" PRINTF(int1);" +" SELECT COUNT(*) INTO int1 FROM TS_TABLE4;" +" PRINTF(int1);" +*/ + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for TPC-A test %lu milliseconds\n", tm - oldtm); + + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE COMMIT_SPEED_TEST () IS" +" " +" BEGIN" +" COMMIT WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*------------------------------------------------------*/ + printf("Will start insert test\n"); + + os_thread_sleep(2000000); + + query = pars_sql( + +" PROCEDURE INSERT_SPEED_TEST () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" int2 := 0;" +" int1 := 0;" +" WHILE int1 < 1000 LOOP" +" INSERT INTO TS_TABLE2 VALUES (int1, int1," +" '123456789012345678901234567890');" +" int1 := int1 + 1;" +" " +" END LOOP;" +" SELECT COUNT(*) INTO int2" +" FROM TS_TABLE2;" +" ASSERT(int1 = int2);" +" " +" COMMIT WORK;" +" " +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for insert test %lu milliseconds\n", tm - oldtm); + + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE DELETE_SPEED_TEST () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" SELECT COUNT(*), SUM(COL22) INTO int1, int2" +" FROM TS_TABLE2" +" CONSISTENT READ;" +" ASSERT(int1 = 1000);" +" ASSERT(int2 = 999 * 500);" +" DELETE FROM TS_TABLE2;" +" " +" SELECT COUNT(*), SUM(COL22) INTO int1, int2" +" FROM TS_TABLE2" +" CONSISTENT READ;" +" ASSERT(int1 = 0);" +" ASSERT(int2 = 0);" +" " +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for delete test %lu milliseconds\n", tm - oldtm); + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + os_thread_sleep(2000000); + + query = pars_sql( + +" PROCEDURE CONSISTENT_READ_TEST () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" SELECT COUNT(*), SUM(COL22) INTO int1, int2" +" FROM TS_TABLE2" +" CONSISTENT READ;" +" ASSERT(int2 = 999 * 500);" +" ASSERT(int1 = 1000);" +" " +" " +" END;" + ); + + query->trx = trx2; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for consistent read test %lu milliseconds\n", + tm - oldtm); + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE ROLLBACK_SPEED_TEST () IS" +" " +" BEGIN" +" ROLLBACK WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback %lu milliseconds\n", tm - oldtm); + + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE UPDATE_SPEED_TEST () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" UPDATE TS_TABLE2 SET COL21 = COL21 + 1000, COL22 = COL22 + 1" +" WHERE COL21 < 1000;" +" UPDATE TS_TABLE2 SET COL21 = COL21, COL22 = COL22;" +" UPDATE TS_TABLE2 SET COL21 = COL21, COL22 = COL22;" +" UPDATE TS_TABLE2 SET COL21 = COL21, COL22 = COL22;" +" UPDATE TS_TABLE2 SET COL21 = COL21, COL22 = COL22;" +" UPDATE TS_TABLE2 SET COL21 = COL21, COL22 = COL22;" +" UPDATE TS_TABLE2 SET COL21 = COL21, COL22 = COL22;" +" UPDATE TS_TABLE2 SET COL21 = COL21, COL22 = COL22;" +" UPDATE TS_TABLE2 SET COL21 = COL21, COL22 = COL22;" +" " +" SELECT SUM(COL21), SUM(COL22) INTO int1, int2" +" FROM TS_TABLE2" +" CONSISTENT READ;" +" ASSERT(int2 = 1000 + 999 * 500);" +" ASSERT(int1 = 1000000 + 999 * 500);" +" UPDATE TS_TABLE2 SET COL21 = COL21 + 1000, COL22 = COL22 + 1" +" WHERE COL21 < 2000;" +" UPDATE TS_TABLE2 SET COL21 = COL21 + 1000, COL22 = COL22 + 1" +" WHERE COL21 < 3000;" +" COMMIT WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for update test %lu milliseconds\n", tm - oldtm); + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + os_thread_sleep(2000000); + + query = pars_sql( + +" PROCEDURE CONSISTENT_READ_TEST () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" SELECT COUNT(*), SUM(COL22) INTO int1, int2" +" FROM TS_TABLE2" +" CONSISTENT READ;" +" ASSERT(int1 = 1000);" +" ASSERT(int2 = 999 * 500);" +" " +" " +" END;" + ); + + query->trx = trx2; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for consistent read test %lu milliseconds\n", + tm - oldtm); + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE COMMIT_SPEED_TEST () IS" +" " +" BEGIN" +" COMMIT WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE2"); */ + /*------------------------------------------------------*/ + /*------------------------------------------------------*/ + os_thread_sleep(2000000); + + query = pars_sql( + +" PROCEDURE CONSISTENT_READ_TEST () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" SELECT COUNT(*), SUM(COL22) INTO int1, int2" +" FROM TS_TABLE2" +" CONSISTENT READ;" +" ASSERT(int1 = 1000);" +" ASSERT(int2 = 999 * 500);" +" " +" " +" END;" + ); + + query->trx = trx2; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for consistent read test %lu milliseconds\n", + tm - oldtm); + /*------------------------------------------------------*/ + printf("Will start insert test2\n"); + os_thread_sleep(2000000); + + query = pars_sql( + +" PROCEDURE INSERT_SPEED_TEST2 () IS" +" int1 INT;" +" int2 INT;" +" " +" BEGIN" +" INSERT INTO TS_TABLE3 SELECT * FROM TS_TABLE2;" +" " +" SELECT COUNT(*) INTO int1" +" FROM TS_TABLE2;" +" SELECT COUNT(*) INTO int2" +" FROM TS_TABLE3;" +" ASSERT(int1 = int2);" +" " +" COMMIT WORK;" +" " +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for insert test2 %lu milliseconds\n", tm - oldtm); + +/* sync_print(); */ + + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE COMMIT_SPEED_TEST () IS" +" " +" BEGIN" +" COMMIT WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*------------------------------------------------------*/ + + query = pars_sql( + +" PROCEDURE JOIN_SPEED_TEST () IS" +" int1 INT;" +" " +" BEGIN" +" SELECT COUNT(*) INTO int1" +" FROM TS_TABLE2, TS_TABLE3" +" WHERE COL21 = COL31;" +" ASSERT(int1 = 1000);" +" " +" COMMIT WORK;" +" " +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for join test %lu milliseconds\n", tm - oldtm); + + /*------------------------------------------------------*/ + + dict_table_print_by_name("TS_TABLE1"); + dict_table_print_by_name("TS_TABLE2"); + +/* + dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); + dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); +*/ + query = pars_sql( + +" PROCEDURE INSERT_TEST () IS" +" var1 CHAR;" +" var2 CHAR;" +" int1 INT;" +" int2 INT;" +" sum1 INT;" +" finished INT;" +" rnd_var1 INT;" +" rnd_var2 INT;" +" " +" DECLARE CURSOR cursor2" +" IS SELECT COL21, COL22" +" FROM TS_TABLE2" +" WHERE COL21 > 5;" +" " +" BEGIN" +" int1 := 0;" +" WHILE int1 < 10 LOOP" +" rnd_var1 := int1;" +" PRINTF('Round '); PRINTF(int1);" +" INSERT INTO TS_TABLE2 VALUES (int1, rnd_var1," +" '123456789012345678901234567890');" +" SELECT COL22 INTO rnd_var2 FROM TS_TABLE2" +" WHERE COL21 = int1;" +" ASSERT(rnd_var1 = rnd_var2);" +" int1 := int1 + 1;" +" END LOOP;" +" " +" PRINTF('First explicit cursor loop:');" +" OPEN cursor2;" +" finished := 0;" +" " +" WHILE finished = 0 LOOP" +" FETCH cursor2 INTO int1, int2;" +" IF cursor2 % NOTFOUND THEN" +" finished := 1;" +" PRINTF('Loop now finished');" +" ELSE" +" PRINTF('Row fetched, values:');" +" PRINTF(int1); PRINTF(int2);" +" ASSERT(int1 = int2);" +" UPDATE TS_TABLE2 SET COL22 = COL22 + 100" +" WHERE CURRENT OF cursor2;" +" END IF;" +" END LOOP;" +" CLOSE cursor2;" +" " +" PRINTF('Second explicit cursor loop:');" +" OPEN cursor2;" +" finished := 0;" +" " +" WHILE finished = 0 LOOP" +" FETCH cursor2 INTO int1, int2;" +" IF cursor2 % NOTFOUND THEN" +" finished := 1;" +" ELSE" +" PRINTF('Row fetched, values:');" +" PRINTF(int1); PRINTF(int2);" +" ASSERT(int1 + 100 = int2);" +" UPDATE TS_TABLE2 SET COL22 = int2 + 100" +" WHERE CURRENT OF cursor2;" +" END IF;" +" END LOOP;" +" CLOSE cursor2;" +" " +" SELECT COUNT(*), SUM(COL22) INTO int1, sum1" +" FROM TS_TABLE2;" +" PRINTF('Now table 2 has this many rows: '); PRINTF(int1);" +" PRINTF('and the sum of COL22: '); PRINTF(sum1);" +" " +" INSERT INTO TS_TABLE3" +" SELECT COL21, COL22 + 10, COL23 FROM TS_TABLE2;" +" " +" SELECT COUNT(*), SUM(COL32) INTO int1, sum1" +" FROM TS_TABLE2, TS_TABLE3" +" WHERE COL21 + 2 = COL31;" +" PRINTF('Join table has this many rows: '); PRINTF(int1);" +" PRINTF('and the sum of COL32: '); PRINTF(sum1);" +" " +" ROLLBACK WORK;" +" " +" SELECT COUNT(*), SUM(COL21) INTO int1, sum1 FROM TS_TABLE2;" +" PRINTF('Now table 2 has this many rows: '); PRINTF(int1);" +" PRINTF('and the sum of COL21: '); PRINTF(sum1);" +" " +" " +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + dict_table_print_by_name("TS_TABLE1"); + dict_table_print_by_name("TS_TABLE2"); + + query = pars_sql( + +" PROCEDURE DELETE_TEST () IS" +" int1 INT;" +" sum1 INT;" +" finished INT;" +" " +" DECLARE CURSOR cursor2" +" IS SELECT" +" FROM TS_TABLE2" +" WHERE COL21 < 10;" +" " +" BEGIN" +" int1 := 0;" +" WHILE int1 < 10 LOOP" +" PRINTF('Round '); PRINTF(int1);" +" INSERT INTO TS_TABLE2 VALUES (int1, int1, TO_CHAR(int1));" +" int1 := int1 + 1;" +" END LOOP;" +" COMMIT WORK;" +" PRINTF('Delete all the rows:');" +" OPEN cursor2;" +" finished := 0;" +" " +" WHILE finished = 0 LOOP" +" FETCH cursor2 INTO;" +" IF cursor2 % NOTFOUND THEN" +" finished := 1;" +" PRINTF('Loop now finished: all rows deleted');" +" ELSE" +" DELETE FROM TS_TABLE2" +" WHERE CURRENT OF cursor2;" +" END IF;" +" END LOOP;" +" CLOSE cursor2;" +" " +" SELECT COUNT(*), SUM(COL22) INTO int1, sum1" +" FROM TS_TABLE2;" +" PRINTF('Now table 2 has this many rows, and their sum is: ');" +" PRINTF(int1); PRINTF(sum1);" +" ASSERT((int1 = 0) AND (sum1 = 0));" +" " +" ROLLBACK WORK;" +" " +" SELECT COUNT(*), SUM(COL22) INTO int1, sum1" +" FROM TS_TABLE2;" +" " +" PRINTF(int1); PRINTF(sum1);" +" ASSERT((int1 = 10) AND (sum1 = 45));" +" COMMIT WORK;" +" DELETE FROM TS_TABLE2 WHERE COL22 = 5;" +" SELECT COUNT(*), SUM(COL22) INTO int1, sum1" +" FROM TS_TABLE2;" +" PRINTF(int1); PRINTF(sum1);" +" ASSERT((int1 = 9) AND (sum1 = 40));" +" DELETE FROM TS_TABLE2 WHERE COL23 = TO_CHAR(6);" +" SELECT COUNT(*), SUM(COL22) INTO int1, sum1" +" FROM TS_TABLE2;" +" PRINTF(int1);" +" PRINTF(sum1);" +" ASSERT((int1 = 8) AND (sum1 = 34));" +" DELETE FROM TS_TABLE2 WHERE COL23 = TO_CHAR(6);" +" SELECT COUNT(*), SUM(COL22) INTO int1, sum1" +" FROM TS_TABLE2;" +" PRINTF(int1);" +" PRINTF(sum1);" +" ASSERT((int1 = 8) AND (sum1 = 34));" +" COMMIT WORK;" +" END;" + ); + + query->trx = trx; + + thr = UT_LIST_GET_FIRST(query->thrs); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(query, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + return(0); +} + +#endif + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + + oldtm = ut_clock(); + + test_c(NULL); + + tm = ut_clock(); + + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} + diff --git a/innobase/btr/ts/tsbtr97.c b/innobase/btr/ts/tsbtr97.c new file mode 100644 index 00000000000..633fb7f22ae --- /dev/null +++ b/innobase/btr/ts/tsbtr97.c @@ -0,0 +1,5080 @@ +/************************************************************************ +Test for the B-tree + +(c) 1996-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "os0proc.h" +#include "sync0sync.h" +#include "ut0mem.h" +#include "mem0mem.h" +#include "mem0pool.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "buf0flu.h" +#include "os0file.h" +#include "os0thread.h" +#include "fil0fil.h" +#include "fsp0fsp.h" +#include "rem0rec.h" +#include "rem0cmp.h" +#include "mtr0mtr.h" +#include "log0log.h" +#include "log0recv.h" +#include "page0page.h" +#include "page0cur.h" +#include "trx0trx.h" +#include "dict0boot.h" +#include "trx0sys.h" +#include "dict0crea.h" +#include "btr0btr.h" +#include "btr0pcur.h" +#include "btr0cur.h" +#include "btr0sea.h" +#include "rem0rec.h" +#include "srv0srv.h" +#include "que0que.h" +#include "com0com.h" +#include "usr0sess.h" +#include "lock0lock.h" +#include "trx0roll.h" +#include "trx0purge.h" +#include "row0ins.h" +#include "row0upd.h" +#include "row0row.h" +#include "row0del.h" +#include "lock0lock.h" +#include "ibuf0ibuf.h" + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[10]; + +mutex_t incs_mutex; +ulint incs; + +byte bigbuf[1000000]; + +#define N_SPACES 2 +#define N_FILES 1 +#define FILE_SIZE 512 /* must be > 512 */ +#define POOL_SIZE 500 +#define COUNTER_OFFSET 1500 + +#define N_LOG_GROUPS 2 +#define N_LOG_FILES 3 +#define LOG_FILE_SIZE 500 + +#define LOOP_SIZE 150 +#define N_THREADS 5 + +#define COUNT 1 + +ulint zero = 0; + +buf_block_t* bl_arr[POOL_SIZE]; + +ulint dummy = 0; + +byte rnd_buf[256 * 256]; + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + ulint i; + + segment = *((ulint*)arg); + + printf("Io handler thread %lu starts\n", segment); + + for (i = 0;; i++) { + fil_aio_wait(segment); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + + } + + return(0); +} + +/************************************************************************* +Creates or opens the log files. */ + +void +create_log_files(void) +/*==================*/ +{ + bool ret; + ulint i, k; + char name[20]; + + printf("--------------------------------------------------------\n"); + printf("Create or open log files\n"); + + strcpy(name, "logfile00"); + + for (k = 0; k < N_LOG_GROUPS; k++) { + for (i = 0; i < N_LOG_FILES; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_AIO, + &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_AIO, &ret); + ut_a(ret); + } else { + ut_a(os_file_set_size(files[i], + 8192 * LOG_FILE_SIZE, 0)); + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k + 100, FIL_LOG); + } + + ut_a(fil_validate()); + + fil_node_create(name, LOG_FILE_SIZE, k + 100); + } + + fil_space_create(name, k + 200, FIL_LOG); + + log_group_init(k, N_LOG_FILES, LOG_FILE_SIZE * UNIV_PAGE_SIZE, + k + 100, k + 200); + } +} + +/************************************************************************* +Creates the files for the file system test and inserts them to the file +system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k, j, c; + char name[20]; + os_thread_t thr[10]; + os_thread_id_t id[10]; + + printf("--------------------------------------------------------\n"); + printf("Create or open database files\n"); + + strcpy(name, "tsfile00"); + + for (k = 0; k < 2 * N_SPACES; k += 2) { + for (i = 0; i < N_FILES; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, + OS_FILE_NORMAL, &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_NORMAL, &ret); + ut_a(ret); + } else { + ut_a(os_file_set_size(files[i], + UNIV_PAGE_SIZE * FILE_SIZE, 0)); + /* Initialize the file contents to a random value */ + + for (j = 0; j < FILE_SIZE; j++) { + for (c = 0; c < UNIV_PAGE_SIZE; c++) { + rnd_buf[c] = 0xFF; + /*(byte) + (ut_rnd_gen_ulint() % 256); */ + } + + os_file_write(files[i], rnd_buf, + UNIV_PAGE_SIZE * j, 0, + UNIV_PAGE_SIZE); + } + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k, FIL_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create(name, FILE_SIZE, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK); + + for (i = 0; i < 9; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/************************************************************************ +Inits space headers of spaces 0 and 2. */ + +void +init_spaces(void) +/*=============*/ +{ + mtr_t mtr; + + mtr_start(&mtr); + + fsp_header_init(0, FILE_SIZE * N_FILES, &mtr); + fsp_header_init(2, FILE_SIZE * N_FILES, &mtr); + + mtr_commit(&mtr); +} + +/********************************************************************* +Test for table creation. */ + +ulint +test1( +/*==*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1. CREATE TABLE WITH 3 COLUMNS AND WITH 3 INDEXES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE1", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND1", 0, + /*DICT_UNIQUE |*/ DICT_CLUSTERED, 1); + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND2", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND3", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +#ifdef notdefined + /*-------------------------------------*/ + /* CREATE YET ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND4", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +#endif +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_5( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.5. CREATE TABLE WITH 3 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE2", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE2", "IND1", 0, + DICT_CLUSTERED | DICT_UNIQUE, 1); + + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_6( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.6. CREATE TABLE WITH 3 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE3", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE3", "IND1", 0, DICT_CLUSTERED, + 2); + dict_mem_index_add_field(index, "COL1", 0); + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_7( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.7. CREATE TABLE WITH 12 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE4", 0, 12); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL4", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL5", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL6", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL7", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL8", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL9", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL10", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL11", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL12", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE4", "IND1", 0, + DICT_CLUSTERED | DICT_UNIQUE, 1); + + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Test for inserts. */ + +ulint +test2( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + dict_index_t* index; +/* ulint size; */ + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2. MASSIVE INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + /* MASSIVE RANDOM INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 7857641) % 200000; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 100 == 0) { + printf( + "********************************Inserted %lu rows\n", i); + ibuf_print(); + } + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); +/* + for (i = 0; i < 10; i++) { + size = ibuf_contract(TRUE); + + printf("%lu bytes will be contracted\n", size); + + os_thread_sleep(1000000); + } +*/ +/* index = dict_table_get_next_index(dict_table_get_first_index(table)); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + index = dict_table_get_next_index(index); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); +*/ +/* dict_table_print_by_name("TS_TABLE1"); */ + + btr_search_print_info(); + + /* Check inserted entries */ + + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < 1 /* *((ulint*)arg) */; i++) { + + rnd = (rnd + 7857641) % 200000; + dtuple_gen_search_tuple3(entry, rnd, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + +/* btr_validate_tree(tree); */ + +/* btr_print_tree(tree, 5); */ + +#ifdef notdefined + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + btr_validate_tree(tree); + +/* btr_search_print_info(); + dict_table_print_by_name("TS_TABLE1"); */ + /*-------------------------------------*/ + + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_1( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ins_node_t* node; + ulint count = 0; + ulint rnd; + dtuple_t* row; +/* buf_frame_t* frame_table[2000]; + dict_tree_t* tree; + dict_index_t* index; + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; */ + + printf("-------------------------------------------------\n"); + printf("TEST 2.1. MASSIVE ASCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + rnd = 0; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 5000 == 0) { + + /* fsp_print(0); */ + /* ibuf_print(); */ + /* buf_print(); */ + + /* buf_print_io(); */ + + tm = ut_clock(); + /* + printf("Wall time for %lu inserts %lu milliseconds\n", + i, tm - oldtm); */ + } + + rnd = rnd + 1; + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + +#ifdef notdefined +/* dict_table_print_by_name("TS_TABLE1"); */ + + ibuf_print(); + + index = dict_table_get_first_index(table); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + /* Check inserted entries */ + + btr_search_print_info(); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ + /* ROLLBACK */ + +/* btr_validate_tree(tree); */ + + for (i = 0; i < POOL_SIZE - 1; i++) { + frame_table[i] = buf_frame_alloc(FALSE); + } + + for (i = 0; i < POOL_SIZE - 1; i++) { + buf_frame_free(frame_table[i]); + } + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); +#endif +#ifdef notdefined + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_search_print_info(); + +#endif + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + /*-------------------------------------*/ + + count++; +/* btr_validate_tree(tree); */ + + if (count < 1) { + goto loop; + } + + mem_heap_free(heap); + + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_2( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + btr_pcur_t pcur; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2.2. MASSIVE DESCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = *((ulint*)arg) + 1; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd - 1) % 200000; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND3500, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 1000 == 0) { +/* printf( + "********************************Inserted %lu rows\n", i); + ibuf_print(); */ + } + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /* Check inserted entries */ + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i + 1, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_validate_tree(tree); +/* dict_table_print_by_name("TS_TABLE1"); */ + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + + btr_validate_tree(tree); + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Multithreaded test for random inserts. */ + +ulint +test2mt( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2MT. MULTITHREADED RANDOM INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + rnd = 78675; +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + if (i % 100 == 0) { + printf("*******Inserted %lu rows\n", i); +/* buf_print(); */ + ibuf_print(); + } + + rnd = (rnd + 7857641) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for multithreaded sequential inserts. */ + +ulint +test2_1mt( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2.1MT. MULTITHREADED ASCENDING INSERT\n"); + + rnd = 8757677; + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + rnd += 98667501; + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 1) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for multithreaded sequential inserts. */ + +ulint +test2_2mt( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2.2MT. MULTITHREADED DESCENDING INSERT\n"); + + rnd = 87677; + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + rnd += 78667; + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd - 1) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + mem_print_info(); + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for updates. */ + +ulint +test3( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + byte* ptr; + ulint len; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 3. UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 3; i++) { + dtuple_gen_test_tuple3(row, i, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + dict_table_print_by_name("TS_TABLE1"); + /*-------------------------------------*/ + /* UPDATE ROWS */ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + dtuple_gen_test_tuple3(row, 1, DTUPLE_TEST_RND30, buf); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + ut_a(DB_SUCCESS == lock_clust_rec_read_check_and_lock(0, + btr_pcur_get_rec(&pcur), + index, LOCK_X, thr)); + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), "updated field", 14); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + mtr_start(&mtr); + + ut_a(btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr)); + + ptr = rec_get_nth_field(btr_pcur_get_rec(&pcur), 5, &len); + + ut_a(ut_memcmp(ptr, "updated field", 14) == 0); + + btr_pcur_commit(&pcur); + + dict_table_print_by_name("TS_TABLE1"); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + dfield_set_data(&(ufield->new_val), "31415926", 9); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + dict_table_print_by_name("TS_TABLE1"); + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); +#ifdef notdefined + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ +#endif + dict_table_print_by_name("TS_TABLE1"); + count++; + + if (count < 1) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Init for update test. */ + +ulint +test4_1(void) +/*=========*/ +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + + printf("-------------------------------------------------\n"); + printf("TEST 4.1. UPDATE INIT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 200; i++) { + + dtuple_gen_test_tuple3(row, i, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + dict_table_print_by_name("TS_TABLE1"); + + return(0); +} + +/************************************************************************* +Checks that the multithreaded update test has rolled back its updates. */ + +void +test4_2(void) +/*=========*/ +{ + dtuple_t* entry; + mem_heap_t* heap; + mem_heap_t* heap2; + mtr_t mtr; + byte buf[32]; + sess_t* sess; + com_endpoint_t* com_endpoint; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + dtuple_t* row; + btr_pcur_t pcur; + rec_t* rec; + + printf("-------------------------------------------------\n"); + printf("TEST 4.2. CHECK UPDATE RESULT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*------------------------------------------*/ + + table = dict_table_get("TS_TABLE1", trx); + + index = dict_table_get_first_index(table); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < 200; i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + rec = btr_pcur_get_rec(&pcur); + + ut_a(0 == cmp_dtuple_rec(entry, rec)); + + heap2 = mem_heap_create(200); + + row = row_build(ROW_COPY_DATA, index, rec, heap2); + + ut_a(30 == dfield_get_len(dtuple_get_nth_field(row, 2))); + ut_a(0 == ut_memcmp( + dfield_get_data(dtuple_get_nth_field(row, 2)), + "12345678901234567890123456789", 30)); + + mem_heap_free(heap2); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +} + +/********************************************************************* +Test for massive updates. */ + +ulint +test4mt( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[4000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 4. MULTITHREADED UPDATES\n"); + + thr_no = *((ulint*)arg); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 999; i++) { + + rnd += 874681; + tuple_no = (rnd % 40) * 5 + thr_no; + + dtuple_gen_search_tuple3(entry, tuple_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("%lu: thread %lu to update row %lu\n", i, thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), buf2, rnd % 200); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + mem_pool_print_info(mem_comm_pool); + + if ((count == 1) && (thr_no != 4)) { + + return(0); + } + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(7000000); + + btr_validate_tree(tree); + + ut_a(trx->conc_state != TRX_ACTIVE); + ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0); + + count++; + + if (count < 2) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for join. */ + +ulint +test6( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ulint count = 0; + dtuple_t* entry; + dict_index_t* index; + dict_tree_t* tree; + btr_pcur_t pcur; + btr_pcur_t pcur2; + mtr_t mtr; + mtr_t mtr2; + ulint rnd; + ulint latch_mode; + + printf("-------------------------------------------------\n"); + printf("TEST 6. MASSIVE EQUIJOIN\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*--------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + /*--------------*/ + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /* Check inserted entries */ + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + table = dict_table_get("TS_TABLE1", trx); + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + oldtm = ut_clock(); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IS, thr)); + + rnd = 98651; + + for (i = 0; i < *((ulint*)arg); i++) { + + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + btr_pcur_store_position(&pcur, &mtr); + + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur), + index)); + + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + if (i % 1211 == 0) { + dummy++; + } + + rnd = 55321; + + dtuple_gen_search_tuple3(entry, rnd % *((ulint*)arg), buf); + +/* if (i == 0) { */ + latch_mode = BTR_SEARCH_LEAF; +/* } else { + latch_mode = BTR_SEARCH_LEAF | BTR_GUESS_LATCH; + } */ + + mtr_start(&mtr2); + + btr_pcur_open(index, entry, PAGE_CUR_LE, latch_mode, + &pcur2, &mtr2); + + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur2), + index)); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur2))); + + mtr_commit(&mtr2); + + mtr_start(&mtr); + + btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + tm = ut_clock(); + printf("Wall time for join of %lu rows %lu milliseconds\n", + i, tm - oldtm); + btr_search_index_print_info(index); + /*-------------------------------------*/ + /* COMMIT */ + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); +/* printf("Wall time for commit %lu milliseconds\n", tm - oldtm); */ + + /*-------------------------------------*/ + count++; +/* btr_validate_tree(tree); */ + + if (count < 3) { + goto loop; + } + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Test for lock wait. Requires Test 4.1 first. */ + +ulint +test7( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + trx_t* trx2; + ulint rnd; + dtuple_t* entry; + dtuple_t* row; + byte buf[100]; + byte buf2[4000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 7. LOCK WAIT\n"); + + thr_no = *((ulint*)arg); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx2 = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + /* UPDATE by trx */ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + ut_a(trx_start(trx2, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 2); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + rnd += 874681; + tuple_no = 3; + + dtuple_gen_search_tuple3(entry, tuple_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), buf2, rnd % 1500); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + tm = ut_clock(); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + + lock_print_info(); + + /*-------------------------------------*/ + /* INSERT by trx2 */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx2; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx2); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx2->sess); + + trx2->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + dtuple_gen_test_tuple3(row, 2, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + /* Insert should be left to wait until trx releases the row lock */ + + que_run_threads(thr); + + tm = ut_clock(); + + lock_validate(); + + lock_print_info(); + + /*-------------------------------------*/ + /* COMMIT of trx */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + + /*-------------------------------------*/ + os_thread_sleep(1000000); + + printf( + "trx2 can now continue to do the insert, after trx committed.\n"); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + + lock_print_info(); + + dict_table_print_by_name("TS_TABLE1"); + + return(0); +} + +/********************************************************************* +Inserts for TPC-A. */ + +ulint +test8A( +/*===*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + btr_pcur_t pcur; + mtr_t mtr; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 8A. 1000 INSERTS FOR TPC-A\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE2", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 1000; i++) { + dtuple_gen_test_tuple_TPC_A(row, rnd, buf); + + rnd = rnd + 1; + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < 1000; i++) { + dtuple_gen_search_tuple_TPC_A(entry, rnd, buf); + + rnd = rnd + 1; + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); + + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + +/* dict_table_print_by_name("TS_TABLE2"); */ + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Test for TPC-A transaction. */ + +ulint +test8( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork1; + que_fork_t* fork2; + que_fork_t* cfork; + dict_table_t* table; + dict_table_t* table2; + que_thr_t* thr; + trx_t* trx; + ulint i; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ins_node_t* inode; + ulint rnd = 0; + + arg = arg; + + printf("-------------------------------------------------\n"); + printf("TEST 8. TPC-A %lu \n", *((ulint*)arg)); + + oldtm = ut_clock(); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + /*-----------------------------------*/ + + fork1 = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork1->trx = trx; + + thr = que_thr_create(fork1, fork1, heap); + + table = dict_table_get("TS_TABLE3", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + inode = ins_node_create(fork1, thr, row, table, heap); + + thr->child = inode; + + row_ins_init_sys_fields_at_sql_compile(inode->row, inode->table, heap); + row_ins_init_sys_fields_at_sql_prepare(inode->row, inode->table, trx); + + inode->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork1, trx->sess); + + trx->graph = fork1; + + mutex_exit(&kernel_mutex); + + fork2 = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork2->trx = trx; + + thr = que_thr_create(fork2, fork2, heap); + + table2 = dict_table_get("TS_TABLE2", trx); + + update = upd_create(1, heap); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 1, table2); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + node = upd_node_create(fork2, thr, table2, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = UPD_NODE_NO_ORD_CHANGE | UPD_NODE_NO_SIZE_CHANGE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork2, trx->sess); + + trx->graph = fork2; + + mutex_exit(&kernel_mutex); + + cfork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + cfork->trx = trx; + + thr = que_thr_create(cfork, cfork, heap); + + thr->child = commit_node_create(cfork, thr, heap); + + oldtm = ut_clock(); + +loop: +/* printf("Round %lu\n", count); */ + + /*-------------------------------------*/ + /* INSERT */ + +/* printf("Trx %lu %lu starts, thr %lu\n", + ut_dulint_get_low(trx->id), + (ulint)trx, + *((ulint*)arg)); */ + + dtuple_gen_test_tuple3(row, count, DTUPLE_TEST_FIXED30, buf); + + ins_node_reset(inode); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork1, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + /*-------------------------------------*/ + /* 3 UPDATES */ + + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IX, thr)); + + for (i = 0; i < 3; i++) { + + rnd += 876751; + + if (count % 1231 == 0) { + dummy++; + } + + dtuple_gen_search_tuple_TPC_A(entry, rnd % 1000, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_LEAF, &pcur, &mtr); + +/* ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); */ + +/* btr_pcur_store_position(&pcur, &mtr); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + ufield = upd_get_nth_field(update, 0); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork2, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + /*-------------------------------------*/ + /* COMMIT */ + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(cfork, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + count++; + + if (count < *((ulint*)arg)) { + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + goto loop; + } + +/* printf("Trx %lu %lu committed\n", ut_dulint_get_low(trx->id), + (ulint)trx); */ + tm = ut_clock(); + printf("Wall time for TPC-A %lu trxs %lu milliseconds\n", + count, tm - oldtm); + + btr_search_index_print_info(index); + btr_search_index_print_info(dict_table_get_first_index(table)); + +/* mem_print_info(); */ + /*-------------------------------------*/ + + +/* dict_table_print_by_name("TS_TABLE2"); + dict_table_print_by_name("TS_TABLE3"); */ + + return(0); +} + +/********************************************************************* +Inserts for TPC-C. */ + +ulint +test9A( +/*===*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; +/* dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; + dict_index_t* index; + dict_tree_t* tree; +*/ + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 9A. INSERTS FOR TPC-C\n"); + +#define TPC_C_TABLE_SIZE 15000 + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE4", trx); + + row = dtuple_create(heap, 12 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < TPC_C_TABLE_SIZE; i++) { + + dtuple_gen_test_tuple_TPC_C(row, rnd, buf); + + rnd = rnd + 1; + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + +#ifdef notdefined + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < TPC_C_TABLE_SIZE; i++) { + + dtuple_gen_search_tuple_TPC_C(entry, rnd, buf); + + rnd = rnd + 1; + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); +#endif + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + +/* dict_table_print_by_name("TS_TABLE4"); */ + +/* mem_heap_free(heap); */ + return(0); +} + +/********************************************************************* +Test for TPC-C transaction. Test 9A must be run first to populate table. */ + +ulint +test9( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork1; + que_fork_t* fork2; + que_fork_t* cfork; + dict_table_t* table; + dict_table_t* table2; + que_thr_t* thr; + trx_t* trx; + ulint j; + ulint i; + byte* ptr; + ulint len; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ins_node_t* inode; + ulint rnd = 0; + byte buf2[240]; + rec_t* rec; + + arg = arg; + + printf("-------------------------------------------------\n"); + printf("TEST 9. TPC-C %lu \n", *((ulint*)arg)); + + oldtm = ut_clock(); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + /*-----------------------------------*/ + + fork1 = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork1->trx = trx; + + thr = que_thr_create(fork1, fork1, heap); + + table = dict_table_get("TS_TABLE3", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + inode = ins_node_create(fork1, thr, row, table, heap); + + thr->child = inode; + + row_ins_init_sys_fields_at_sql_compile(inode->row, inode->table, heap); + row_ins_init_sys_fields_at_sql_prepare(inode->row, inode->table, trx); + + inode->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork1, trx->sess); + + trx->graph = fork1; + + mutex_exit(&kernel_mutex); + + fork2 = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork2->trx = trx; + + thr = que_thr_create(fork2, fork2, heap); + + table2 = dict_table_get("TS_TABLE4", trx); + + update = upd_create(3, heap); + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 1, table2); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table2); + ufield = upd_get_nth_field(update, 2); + + upd_field_set_col_no(ufield, 1, table2); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + node = upd_node_create(fork2, thr, table2, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = UPD_NODE_NO_ORD_CHANGE | UPD_NODE_NO_SIZE_CHANGE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork2, trx->sess); + + trx->graph = fork2; + + mutex_exit(&kernel_mutex); + + cfork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + cfork->trx = trx; + + thr = que_thr_create(cfork, cfork, heap); + + thr->child = commit_node_create(cfork, thr, heap); + + oldtm = ut_clock(); +loop: + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IS, thr)); + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IX, thr)); + +/* printf("Round %lu\n", count); */ + +for (j = 0; j < 13; j++) { + + /*-------------------------------------*/ + /* SELECT FROM 'ITEM' */ + + rnd += 876751; + + dtuple_gen_search_tuple_TPC_C(entry, rnd % TPC_C_TABLE_SIZE, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_S, thr); + ut_a(err == DB_SUCCESS); + + rec = btr_pcur_get_rec(&pcur); + + for (i = 0; i < 5; i++) { + ptr = rec_get_nth_field(rec, i + 2, &len); + + ut_memcpy(buf2 + i * 24, ptr, len); + } + + mtr_commit(&mtr); + + /*-------------------------------------*/ + /* UPDATE 'STOCK' */ + + rnd += 876751; + + if (count % 1231 == 0) { + dummy++; + } + + dtuple_gen_search_tuple_TPC_C(entry, rnd % TPC_C_TABLE_SIZE, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_LEAF, &pcur, &mtr); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + +/* btr_pcur_store_position(&pcur, &mtr); */ + + rec = btr_pcur_get_rec(&pcur); + + for (i = 0; i < 10; i++) { + ptr = rec_get_nth_field(rec, i + 2, &len); + + ut_memcpy(buf2 + i * 24, ptr, len); + } + +/* btr_pcur_commit(&pcur); */ + +/* err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); */ + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur), + index)); +/* ut_a(err == DB_SUCCESS); */ + + ufield = upd_get_nth_field(update, 0); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + ufield = upd_get_nth_field(update, 1); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + ufield = upd_get_nth_field(update, 2); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork2, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + btr_pcur_close(&pcur); + /*-------------------------------------*/ + /* INSERT INTO 'ORDERLINE' */ + +/* printf("Trx %lu %lu starts, thr %lu\n", + ut_dulint_get_low(trx->id), + (ulint)trx, + *((ulint*)arg)); */ + + dtuple_gen_test_tuple3(row, count * 13 + j, DTUPLE_TEST_FIXED30, buf); + + ins_node_reset(inode); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork1, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +} + /*-------------------------------------*/ + /* COMMIT */ + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(cfork, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* printf("Trx %lu %lu committed\n", ut_dulint_get_low(trx->id), + (ulint)trx); */ + count++; + + if (count < *((ulint*)arg)) { + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + goto loop; + } + + tm = ut_clock(); + printf("Wall time for TPC-C %lu trxs %lu milliseconds\n", + count, tm - oldtm); + + btr_search_index_print_info(index); + btr_search_index_print_info(dict_table_get_first_index(table)); + +/* mem_print_info(); */ + /*-------------------------------------*/ +/* dict_table_print_by_name("TS_TABLE2"); + dict_table_print_by_name("TS_TABLE3"); */ + + return(0); +} + +/********************************************************************* +Init for purge test. */ + +ulint +test10_1( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint thr_no; + + thr_no = *((ulint*)arg); + + printf("-------------------------------------------------\n"); + printf("TEST 10.1. PURGE INIT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 200; i++) { + + dtuple_gen_test_tuple3(row, i * 100 + thr_no, + DTUPLE_TEST_FIXED30, buf); + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_2( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[1000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.2. PURGE TEST UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(2, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + tuple_no = i; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + dfield_set_data(&(ufield->new_val), dfield_get_data( + dtuple_get_nth_field(entry, 0)), + dfield_get_len( + dtuple_get_nth_field(entry, 0))); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table); + + rnd += 98326761; + + dfield_set_data(&(ufield->new_val), buf2, rnd % 200); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + fsp_validate(0); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + count++; + + if (count < 1) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_2_r( +/*=======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[1000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.2. PURGE TEST UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(2, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + tuple_no = i; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + dfield_set_data(&(ufield->new_val), dfield_get_data( + dtuple_get_nth_field(entry, 0)), + dfield_get_len( + dtuple_get_nth_field(entry, 0))); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table); + + rnd += 98326761; + + dfield_set_data(&(ufield->new_val), buf2, rnd % 2000); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + fsp_validate(0); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + + mem_pool_print_info(mem_comm_pool); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(2000000); + + count++; + + if (count < 1) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_3( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + btr_pcur_t pcur; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + del_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.3. PURGE TEST DELETES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + node = del_node_create(fork, thr, table, &pcur, heap); + thr->child = node; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + rnd = i; + tuple_no = rnd; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu delete markings %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_5( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + btr_pcur_t pcur; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + del_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.5. PURGE TEST UNCOMMITTED DELETES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + node = del_node_create(fork, thr, table, &pcur, heap); + thr->child = node; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 50; i++) { + + rnd = i; + tuple_no = rnd % 100; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu delete markings %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + return(0); +} + +/********************************************************************* +Multithreaded test for purge. */ + +ulint +test10mt( +/*=====*/ + void* arg) +{ + ulint i; + ulint thr_no; + + thr_no = *((ulint*)arg); + + printf("Thread %lu starts purge test\n", thr_no); + + for (i = 0; i < 2; i++) { + test10_1(arg); + + sync_print(); + + fsp_validate(0); + + test10_2_r(arg); + sync_print(); + + test10_2(arg); + sync_print(); + + lock_validate(); + + test10_3(arg); + sync_print(); + } + + printf("Thread %lu ends purge test\n", thr_no); + + return(0); +} + +/********************************************************************* +Purge test. */ + +ulint +test10_4( +/*=====*/ + void* arg) +{ + ulint i; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 10.4. PURGE TEST\n"); + + for (i = 0; i < 30; i++) { + trx_purge(); + + printf("%lu pages purged\n", purge_sys->n_pages_handled); + + os_thread_sleep(5000000); + } + +/* dict_table_print_by_name("TS_TABLE1"); */ + + return(0); +} + +/********************************************************************* +This thread is used to test insert buffer merge. */ + +ulint +test_ibuf_merge( +/*============*/ + void* arg) +{ + ulint sum_sizes; + ulint volume; + + ut_ad(arg); + + printf("Starting ibuf merge\n"); + + sum_sizes = 0; + volume = 1; + + while (volume) { + volume = ibuf_contract(FALSE); + + sum_sizes += volume; + } + + printf("Ibuf merged %lu bytes\n", sum_sizes); + + os_thread_sleep(5000000); + + return(0); +} + +/********************************************************************* +This thread is used to measure contention of latches. */ + +ulint +test_measure_cont( +/*==============*/ + void* arg) +{ + ulint i, j; + ulint count; + + ut_ad(arg); + + printf("Starting contention measurement\n"); + + for (i = 0; i < 1000; i++) { + count = 0; + + for (j = 0; j < 100; j++) { + + os_thread_sleep(10000); + + if ((&(buf_pool->mutex))->lock_word) { + + count++; + } + } + + printf("Mutex reserved %lu of %lu peeks\n", count, j); + } + + return(0); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + os_thread_id_t id[10]; + ulint n1000[10]; + ulint i; + ulint n5000 = 500; + ulint n2; + char buf[100]; + +/* buf_debug_prints = TRUE; */ + log_do_write = TRUE; + btr_search_use_hash = TRUE; + log_debug_writes = TRUE; + + srv_boot("initfile"); + os_aio_init(576, 9, 100); + fil_init(25); + buf_pool_init(POOL_SIZE, POOL_SIZE); + fsp_init(); + log_init(); + lock_sys_create(1024); + + create_files(); + create_log_files(); + + init_spaces(); + + sess_sys_init_at_db_start(); + + trx_sys_create(); + + dict_create(); + + log_make_checkpoint_at(ut_dulint_max); +/* log_debug_writes = TRUE; */ + +/* os_thread_sleep(500000); */ + + oldtm = ut_clock(); + + ut_rnd_set_seed(19); + + test1(NULL); +/* test1_5(NULL); + test1_6(NULL); + test1_7(NULL); */ + +/* for (i = 0; i < 2; i++) { + + n1000[i] = i; + id[i] = id[i]; + + os_thread_create(test10mt, n1000 + i, id + i); + } +*/ + i = 4; + + n1000[i] = i; + id[i] = id[i]; + +/* os_thread_create(test10_4, n1000 + i, id + i); */ + + i = 5; + +/* test10mt(&i); + + i = 6; + + test10mt(&i); + + trx_purge(); + printf("%lu pages purged\n", purge_sys->n_pages_handled); + + dict_table_print_by_name("TS_TABLE1"); */ + +/* os_thread_create(test_measure_cont, &n3, id + 0); */ + +/* mem_print_info(); */ + + log_make_checkpoint_at(ut_dulint_max); + + n2 = 100; + +/* test2_1(&n2); + + log_flush_up_to(ut_dulint_max, LOG_WAIT_ALL_GROUPS); */ + +/* sync_print(); + + test9A(&n2); + + sync_print(); + + log_print(); + + test9(&n2); + + log_print(); + + sync_print(); */ +/* test6(&n2); */ + +/* test2_2(&n2); */ + +/* test3(&n2); */ + +/* mem_print_info(); */ + + log_archive_stop(); + log_archive_start(); + + ut_a(DB_SUCCESS == log_switch_backup_state_on()); + + printf("Type: kukkuu<enter>\n"); + scanf("%s", buf); + + ut_a(DB_SUCCESS == log_switch_backup_state_off()); + + for (i = 0; i < 2; i++) { + + n1000[i] = 500 + 10 * i; + id[i] = id[i]; +/* + os_thread_create(test2mt, n1000 + i, id + i); + os_thread_create(test2_1mt, n1000 + i, id + i); + os_thread_create(test2_2mt, n1000 + i, id + i); +*/ } + + n2 = 5000; + +/* fsp_print(0); */ + + test2_1(&n2); + + for (i = 0; i < 20; i++) { + log_archive_stop(); + log_archive_start(); + } + +/* test2(&n2); + test2(&n2); */ + +/* buf_print(); + ibuf_print(); + rw_lock_list_print_info(); + mutex_list_print_info(); */ + +/* dict_table_print_by_name("TS_TABLE1"); */ + +/* mem_print_info(); */ +/* + n2 = 100; + + test4_1(); + test4_2(); + + for (i = 0; i < 2; i++) { + n1000[i] = i; + id[i] = id[i]; + os_thread_create(test4mt, n1000 + i, id + i); + } + + n2 = 4; + test4mt(&n2); + + log_archive_stop(); + log_archive_start(); + + test4mt(&n2); +*/ +/* test4_2(); */ +/* + lock_print_info(); +*/ +/* test7(&n2); */ + +/* os_thread_sleep(25000000); */ + +/* ut_a(DB_SUCCESS == log_switch_backup_state_off()); */ + +/* recv_compare_spaces(0, 1, 100); */ + + log_flush_up_to(ut_dulint_max, LOG_WAIT_ALL_GROUPS); + + printf("Type: kukkuu<enter>\n"); + scanf("%s", buf); + + buf_flush_batch(BUF_FLUSH_LIST, ULINT_MAX, ut_dulint_max); + buf_flush_wait_batch_end(BUF_FLUSH_LIST); + +/* log_make_checkpoint_at(ut_dulint_max); */ + +/* dict_table_print_by_name("TS_TABLE1"); */ + +/* buf_print(); */ + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/btr/ts/tsbtrfull.c b/innobase/btr/ts/tsbtrfull.c new file mode 100644 index 00000000000..fc8bbb7bffc --- /dev/null +++ b/innobase/btr/ts/tsbtrfull.c @@ -0,0 +1,4925 @@ +/************************************************************************ +Test for the B-tree + +(c) 1994-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "os0proc.h" +#include "sync0sync.h" +#include "ut0mem.h" +#include "mem0mem.h" +#include "mem0pool.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "os0file.h" +#include "os0thread.h" +#include "fil0fil.h" +#include "fsp0fsp.h" +#include "rem0rec.h" +#include "rem0cmp.h" +#include "mtr0mtr.h" +#include "log0log.h" +#include "page0page.h" +#include "page0cur.h" +#include "trx0trx.h" +#include "dict0boot.h" +#include "trx0sys.h" +#include "dict0crea.h" +#include "btr0btr.h" +#include "btr0pcur.h" +#include "btr0cur.h" +#include "btr0sea.h" +#include "rem0rec.h" +#include "srv0srv.h" +#include "que0que.h" +#include "com0com.h" +#include "usr0sess.h" +#include "lock0lock.h" +#include "trx0roll.h" +#include "trx0purge.h" +#include "row0ins.h" +#include "row0upd.h" +#include "row0row.h" +#include "row0del.h" +#include "lock0lock.h" +#include "ibuf0ibuf.h" + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[10]; + +mutex_t incs_mutex; +ulint incs; + +byte bigbuf[1000000]; + +#define N_SPACES 2 /* must be >= 2 */ +#define N_FILES 1 +#define FILE_SIZE 8096 /* must be > 512 */ +#define POOL_SIZE 1524 +#define IBUF_SIZE 200 +#define COUNTER_OFFSET 1500 + +#define LOOP_SIZE 150 +#define N_THREADS 5 + +#define COUNT 1 + +ulint zero = 0; + +buf_block_t* bl_arr[POOL_SIZE]; + +ulint dummy = 0; + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + void* mess; + ulint i; + bool ret; + + segment = *((ulint*)arg); + + printf("Io handler thread %lu starts\n", segment); + + for (i = 0;; i++) { + fil_aio_wait(segment); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + + } + + return(0); +} + +/************************************************************************* +Creates the files for the file system test and inserts them to the file +system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k; + char name[20]; + os_thread_t thr[10]; + os_thread_id_t id[10]; + + printf("--------------------------------------------------------\n"); + printf("Create or open database files\n"); + + strcpy(name, "tsfile00"); + + for (k = 0; k < N_SPACES; k++) { + for (i = 0; i < N_FILES; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, + OS_FILE_TABLESPACE, &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, + OS_FILE_TABLESPACE, &ret); + ut_a(ret); + } else { + if (k == 1) { + ut_a(os_file_set_size(files[i], + 8192 * IBUF_SIZE, 0)); + } else { + ut_a(os_file_set_size(files[i], + 8192 * FILE_SIZE, 0)); + } + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k, OS_FILE_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create(name, FILE_SIZE, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK); + + for (i = 0; i < 9; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/************************************************************************ +Inits space headers of spaces 0 and 1. */ + +void +init_spaces(void) +/*=============*/ +{ + mtr_t mtr; + + mtr_start(&mtr); + + fsp_header_init(0, FILE_SIZE * N_FILES, &mtr); + fsp_header_init(1, IBUF_SIZE, &mtr); + + mtr_commit(&mtr); +} + +/********************************************************************* +Test for table creation. */ + +ulint +test1( +/*==*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1. CREATE TABLE WITH 3 COLUMNS AND WITH 3 INDEXES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE1", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND1", 0, + DICT_UNIQUE | DICT_CLUSTERED, 1); + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND2", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND3", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +#ifdef notdefined + /*-------------------------------------*/ + /* CREATE YET ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND4", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +#endif +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_5( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.5. CREATE TABLE WITH 3 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE2", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE2", "IND1", 0, + DICT_CLUSTERED | DICT_UNIQUE, 1); + + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_6( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.6. CREATE TABLE WITH 3 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE3", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE3", "IND1", 0, DICT_CLUSTERED, + 2); + dict_mem_index_add_field(index, "COL1", 0); + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_7( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.7. CREATE TABLE WITH 12 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE4", 0, 12); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL4", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL5", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL6", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL7", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL8", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL9", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL10", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL11", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL12", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE4", "IND1", 0, + DICT_CLUSTERED | DICT_UNIQUE, 1); + + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Test for inserts. */ + +ulint +test2( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + dict_index_t* index; +/* ulint size; */ + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2. MASSIVE INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + /* MASSIVE RANDOM INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 7857641) % 200000; + + dtuple_gen_test_tuple3(row, rnd, + DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 1000 == 0) { + printf( + "********************************Inserted %lu rows\n", i); + ibuf_print(); + } + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); +/* + for (i = 0; i < 10; i++) { + size = ibuf_contract(TRUE); + + printf("%lu bytes will be contracted\n", size); + + os_thread_sleep(1000000); + } +*/ + index = dict_table_get_next_index(dict_table_get_first_index(table)); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + index = dict_table_get_next_index(index); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + btr_search_print_info(); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 7857641) % 200000; + dtuple_gen_search_tuple3(entry, rnd, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); + +/* btr_print_tree(tree, 5); */ + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + btr_validate_tree(tree); + +/* btr_search_print_info(); + dict_table_print_by_name("TS_TABLE1"); */ + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_1( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ins_node_t* node; + ulint count = 0; + ulint rnd; + dtuple_t* row; +/* dict_tree_t* tree; + dict_index_t* index; + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; */ + + printf("-------------------------------------------------\n"); + printf("TEST 2.1. MASSIVE ASCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 5000 == 0) { + /* ibuf_print(); */ + /* buf_print(); */ + + /* buf_print_io(); */ + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", + i, tm - oldtm); + } + + rnd = rnd + 1; + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + +#ifdef notdefined +/* dict_table_print_by_name("TS_TABLE1"); */ + + ibuf_print(); + + index = dict_table_get_first_index(table); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + /* Check inserted entries */ + + btr_search_print_info(); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); +#endif +#ifdef notdefined + /*-------------------------------------*/ + /* ROLLBACK */ + +/* btr_validate_tree(tree); */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_search_print_info(); + +#endif + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + /*-------------------------------------*/ + + count++; +/* btr_validate_tree(tree); */ + + if (count < 1) { + goto loop; + } + + mem_heap_free(heap); + + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_2( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + btr_pcur_t pcur; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2.2. MASSIVE DESCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = *((ulint*)arg) + 1; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd - 1) % 200000; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 1000 == 0) { +/* printf( + "********************************Inserted %lu rows\n", i); + ibuf_print(); */ + } + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /* Check inserted entries */ + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i + 1, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_validate_tree(tree); +/* dict_table_print_by_name("TS_TABLE1"); */ + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + + btr_validate_tree(tree); + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Multithreaded test for random inserts. */ + +ulint +test2mt( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2MT. MULTITHREADED RANDOM INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + rnd = 78675; +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + if (i % 100 == 0) { +/* buf_print(); */ +/* ibuf_print(); */ + } + + rnd = (rnd + 7857641) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for multithreaded sequential inserts. */ + +ulint +test2_1mt( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2.1MT. MULTITHREADED ASCENDING INSERT\n"); + + rnd = 8757677; + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + rnd += 98667501; + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 1) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for multithreaded sequential inserts. */ + +ulint +test2_2mt( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2.2MT. MULTITHREADED DESCENDING INSERT\n"); + + rnd = 87677; + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + rnd += 78667; + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd - 1) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + mem_print_info(); + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for updates. */ + +ulint +test3( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + byte* ptr; + ulint len; + ulint err; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 3. UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 3; i++) { + dtuple_gen_test_tuple3(row, i, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + dict_table_print_by_name("TS_TABLE1"); + /*-------------------------------------*/ + /* UPDATE ROWS */ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + dtuple_gen_test_tuple3(row, 1, DTUPLE_TEST_RND30, buf); + + entry = dtuple_create(heap, 2); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + dfield_copy(dtuple_get_nth_field(entry, 1), + dtuple_get_nth_field(row, 1)); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), "updated field", 14); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + mtr_start(&mtr); + + ut_a(btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr)); + + ptr = rec_get_nth_field(btr_pcur_get_rec(&pcur), 5, &len); + + ut_a(ut_memcmp(ptr, "updated field", 14) == 0); + + btr_pcur_commit(&pcur); + + dict_table_print_by_name("TS_TABLE1"); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + dfield_set_data(&(ufield->new_val), "31415926", 9); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + dict_table_print_by_name("TS_TABLE1"); + /*-------------------------------------*/ + /* ROLLBACK */ +#ifdef notdefined + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ +#endif + dict_table_print_by_name("TS_TABLE1"); + count++; + + if (count < 1) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Init for update test. */ + +ulint +test4_1(void) +/*=========*/ +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + + printf("-------------------------------------------------\n"); + printf("TEST 4.1. UPDATE INIT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 200; i++) { + + dtuple_gen_test_tuple3(row, i, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + dict_table_print_by_name("TS_TABLE1"); + + return(0); +} + +/************************************************************************* +Checks that the multithreaded update test has rolled back its updates. */ + +void +test4_2(void) +/*=========*/ +{ + dtuple_t* entry; + mem_heap_t* heap; + mem_heap_t* heap2; + mtr_t mtr; + byte buf[32]; + sess_t* sess; + com_endpoint_t* com_endpoint; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + dtuple_t* row; + btr_pcur_t pcur; + rec_t* rec; + + printf("-------------------------------------------------\n"); + printf("TEST 4.2. CHECK UPDATE RESULT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*------------------------------------------*/ + + table = dict_table_get("TS_TABLE1", trx); + + index = dict_table_get_first_index(table); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < 200; i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + rec = btr_pcur_get_rec(&pcur); + + ut_a(0 == cmp_dtuple_rec(entry, rec)); + + heap2 = mem_heap_create(200); + + row = row_build(ROW_COPY_DATA, index, rec, heap2); + + ut_a(30 == dfield_get_len(dtuple_get_nth_field(row, 2))); + ut_a(0 == ut_memcmp( + dfield_get_data(dtuple_get_nth_field(row, 2)), + "12345678901234567890123456789", 30)); + + mem_heap_free(heap2); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +} + +/********************************************************************* +Test for massive updates. */ + +ulint +test4mt( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[4000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 4. MULTITHREADED UPDATES\n"); + + thr_no = *((ulint*)arg); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 300; i++) { + + rnd += 874681; + tuple_no = (rnd % 40) * 5 + thr_no; + + dtuple_gen_search_tuple3(entry, tuple_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), buf2, rnd % 3000); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + mem_pool_print_info(mem_comm_pool); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(2000000); + + btr_validate_tree(tree); + + ut_a(trx->conc_state != TRX_ACTIVE); + ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0); + + count++; + + if (count < 2) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for join. */ + +ulint +test6( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ulint count = 0; + dtuple_t* entry; + dict_index_t* index; + dict_tree_t* tree; + btr_pcur_t pcur; + btr_pcur_t pcur2; + mtr_t mtr; + mtr_t mtr2; + ulint rnd; + ulint latch_mode; + + printf("-------------------------------------------------\n"); + printf("TEST 6. MASSIVE EQUIJOIN\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*--------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + /*--------------*/ + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /* Check inserted entries */ + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + table = dict_table_get("TS_TABLE1", trx); + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + oldtm = ut_clock(); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IS, thr)); + + rnd = 98651; + + for (i = 0; i < *((ulint*)arg); i++) { + + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + btr_pcur_store_position(&pcur, &mtr); + + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur), + index)); + + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + if (i % 1211 == 0) { + dummy++; + } + + rnd = 55321; + + dtuple_gen_search_tuple3(entry, rnd % *((ulint*)arg), buf); + +/* if (i == 0) { */ + latch_mode = BTR_SEARCH_LEAF; +/* } else { + latch_mode = BTR_SEARCH_LEAF | BTR_GUESS_LATCH; + } */ + + mtr_start(&mtr2); + + btr_pcur_open(index, entry, PAGE_CUR_LE, latch_mode, + &pcur2, &mtr2); + + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur2), + index)); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur2))); + + mtr_commit(&mtr2); + + mtr_start(&mtr); + + btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + tm = ut_clock(); + printf("Wall time for join of %lu rows %lu milliseconds\n", + i, tm - oldtm); + btr_search_index_print_info(index); + /*-------------------------------------*/ + /* COMMIT */ + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); +/* printf("Wall time for commit %lu milliseconds\n", tm - oldtm); */ + + /*-------------------------------------*/ + count++; +/* btr_validate_tree(tree); */ + + if (count < 3) { + goto loop; + } + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Test for lock wait. Requires Test 4.1 first. */ + +ulint +test7( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + trx_t* trx2; + ulint rnd; + dtuple_t* entry; + dtuple_t* row; + byte buf[100]; + byte buf2[4000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 7. LOCK WAIT\n"); + + thr_no = *((ulint*)arg); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx2 = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + /* UPDATE by trx */ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + ut_a(trx_start(trx2, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 2); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + rnd += 874681; + tuple_no = 3; + + dtuple_gen_search_tuple3(entry, tuple_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), buf2, rnd % 1500); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + tm = ut_clock(); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + + lock_print_info(); + + /*-------------------------------------*/ + /* INSERT by trx2 */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx2; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx2); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx2->sess); + + trx2->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + dtuple_gen_test_tuple3(row, 2, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + /* Insert should be left to wait until trx releases the row lock */ + + que_run_threads(thr); + + tm = ut_clock(); + + lock_validate(); + + lock_print_info(); + + /*-------------------------------------*/ + /* COMMIT of trx */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + + /*-------------------------------------*/ + os_thread_sleep(1000000); + + printf( + "trx2 can now continue to do the insert, after trx committed.\n"); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + + lock_print_info(); + + dict_table_print_by_name("TS_TABLE1"); + + return(0); +} + +/********************************************************************* +Inserts for TPC-A. */ + +ulint +test8A( +/*===*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + btr_pcur_t pcur; + mtr_t mtr; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 8A. 1000 INSERTS FOR TPC-A\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE2", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 1000; i++) { + dtuple_gen_test_tuple_TPC_A(row, rnd, buf); + + rnd = rnd + 1; + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < 1000; i++) { + dtuple_gen_search_tuple_TPC_A(entry, rnd, buf); + + rnd = rnd + 1; + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); + + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + +/* dict_table_print_by_name("TS_TABLE2"); */ + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Test for TPC-A transaction. */ + +ulint +test8( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork1; + que_fork_t* fork2; + que_fork_t* cfork; + dict_table_t* table; + dict_table_t* table2; + que_thr_t* thr; + trx_t* trx; + ulint i; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ins_node_t* inode; + ulint rnd = 0; + + arg = arg; + + printf("-------------------------------------------------\n"); + printf("TEST 8. TPC-A %lu \n", *((ulint*)arg)); + + oldtm = ut_clock(); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + /*-----------------------------------*/ + + fork1 = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork1->trx = trx; + + thr = que_thr_create(fork1, fork1, heap); + + table = dict_table_get("TS_TABLE3", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + inode = ins_node_create(fork1, thr, row, table, heap); + + thr->child = inode; + + row_ins_init_sys_fields_at_sql_compile(inode->row, inode->table, heap); + row_ins_init_sys_fields_at_sql_prepare(inode->row, inode->table, trx); + + inode->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork1, trx->sess); + + trx->graph = fork1; + + mutex_exit(&kernel_mutex); + + fork2 = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork2->trx = trx; + + thr = que_thr_create(fork2, fork2, heap); + + table2 = dict_table_get("TS_TABLE2", trx); + + update = upd_create(1, heap); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 1, table2); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + node = upd_node_create(fork2, thr, table2, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = UPD_NODE_NO_ORD_CHANGE | UPD_NODE_NO_SIZE_CHANGE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork2, trx->sess); + + trx->graph = fork2; + + mutex_exit(&kernel_mutex); + + cfork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + cfork->trx = trx; + + thr = que_thr_create(cfork, cfork, heap); + + thr->child = commit_node_create(cfork, thr, heap); + + oldtm = ut_clock(); + +loop: +/* printf("Round %lu\n", count); */ + + /*-------------------------------------*/ + /* INSERT */ + +/* printf("Trx %lu %lu starts, thr %lu\n", + ut_dulint_get_low(trx->id), + (ulint)trx, + *((ulint*)arg)); */ + + dtuple_gen_test_tuple3(row, count, DTUPLE_TEST_FIXED30, buf); + + ins_node_reset(inode); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork1, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + /*-------------------------------------*/ + /* 3 UPDATES */ + + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IX, thr)); + + for (i = 0; i < 3; i++) { + + rnd += 876751; + + if (count % 1231 == 0) { + dummy++; + } + + dtuple_gen_search_tuple_TPC_A(entry, rnd % 1000, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_LEAF, &pcur, &mtr); + +/* ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); */ + +/* btr_pcur_store_position(&pcur, &mtr); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + ufield = upd_get_nth_field(update, 0); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork2, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + /*-------------------------------------*/ + /* COMMIT */ + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(cfork, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + count++; + + if (count < *((ulint*)arg)) { + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + goto loop; + } + +/* printf("Trx %lu %lu committed\n", ut_dulint_get_low(trx->id), + (ulint)trx); */ + tm = ut_clock(); + printf("Wall time for TPC-A %lu trxs %lu milliseconds\n", + count, tm - oldtm); + + btr_search_index_print_info(index); + btr_search_index_print_info(dict_table_get_first_index(table)); + +/* mem_print_info(); */ + /*-------------------------------------*/ + + +/* dict_table_print_by_name("TS_TABLE2"); + dict_table_print_by_name("TS_TABLE3"); */ + + return(0); +} + +/********************************************************************* +Inserts for TPC-C. */ + +ulint +test9A( +/*===*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; +/* dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; + dict_index_t* index; + dict_tree_t* tree; +*/ + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 9A. INSERTS FOR TPC-C\n"); + +#define TPC_C_TABLE_SIZE 15000 + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE4", trx); + + row = dtuple_create(heap, 12 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < TPC_C_TABLE_SIZE; i++) { + + dtuple_gen_test_tuple_TPC_C(row, rnd, buf); + + rnd = rnd + 1; + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + +#ifdef notdefined + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < TPC_C_TABLE_SIZE; i++) { + + dtuple_gen_search_tuple_TPC_C(entry, rnd, buf); + + rnd = rnd + 1; + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); +#endif + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + +/* dict_table_print_by_name("TS_TABLE4"); */ + +/* mem_heap_free(heap); */ + return(0); +} + +/********************************************************************* +Test for TPC-C transaction. Test 9A must be run first to populate table. */ + +ulint +test9( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork1; + que_fork_t* fork2; + que_fork_t* cfork; + dict_table_t* table; + dict_table_t* table2; + que_thr_t* thr; + trx_t* trx; + ulint j; + ulint i; + byte* ptr; + ulint len; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ins_node_t* inode; + ulint rnd = 0; + byte buf2[240]; + rec_t* rec; + + arg = arg; + + printf("-------------------------------------------------\n"); + printf("TEST 9. TPC-C %lu \n", *((ulint*)arg)); + + oldtm = ut_clock(); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + /*-----------------------------------*/ + + fork1 = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork1->trx = trx; + + thr = que_thr_create(fork1, fork1, heap); + + table = dict_table_get("TS_TABLE3", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + inode = ins_node_create(fork1, thr, row, table, heap); + + thr->child = inode; + + row_ins_init_sys_fields_at_sql_compile(inode->row, inode->table, heap); + row_ins_init_sys_fields_at_sql_prepare(inode->row, inode->table, trx); + + inode->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork1, trx->sess); + + trx->graph = fork1; + + mutex_exit(&kernel_mutex); + + fork2 = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork2->trx = trx; + + thr = que_thr_create(fork2, fork2, heap); + + table2 = dict_table_get("TS_TABLE4", trx); + + update = upd_create(3, heap); + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 1, table2); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table2); + ufield = upd_get_nth_field(update, 2); + + upd_field_set_col_no(ufield, 1, table2); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + node = upd_node_create(fork2, thr, table2, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = UPD_NODE_NO_ORD_CHANGE | UPD_NODE_NO_SIZE_CHANGE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork2, trx->sess); + + trx->graph = fork2; + + mutex_exit(&kernel_mutex); + + cfork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + cfork->trx = trx; + + thr = que_thr_create(cfork, cfork, heap); + + thr->child = commit_node_create(cfork, thr, heap); + + oldtm = ut_clock(); +loop: + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IS, thr)); + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IX, thr)); + +/* printf("Round %lu\n", count); */ + +for (j = 0; j < 13; j++) { + + /*-------------------------------------*/ + /* SELECT FROM 'ITEM' */ + + rnd += 876751; + + dtuple_gen_search_tuple_TPC_C(entry, rnd % TPC_C_TABLE_SIZE, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_S, thr); + ut_a(err == DB_SUCCESS); + + rec = btr_pcur_get_rec(&pcur); + + for (i = 0; i < 5; i++) { + ptr = rec_get_nth_field(rec, i + 2, &len); + + ut_memcpy(buf2 + i * 24, ptr, len); + } + + mtr_commit(&mtr); + + /*-------------------------------------*/ + /* UPDATE 'STOCK' */ + + rnd += 876751; + + if (count % 1231 == 0) { + dummy++; + } + + dtuple_gen_search_tuple_TPC_C(entry, rnd % TPC_C_TABLE_SIZE, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_LEAF, &pcur, &mtr); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + +/* btr_pcur_store_position(&pcur, &mtr); */ + + rec = btr_pcur_get_rec(&pcur); + + for (i = 0; i < 10; i++) { + ptr = rec_get_nth_field(rec, i + 2, &len); + + ut_memcpy(buf2 + i * 24, ptr, len); + } + +/* btr_pcur_commit(&pcur); */ + +/* err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); */ + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur), + index)); +/* ut_a(err == DB_SUCCESS); */ + + ufield = upd_get_nth_field(update, 0); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + ufield = upd_get_nth_field(update, 1); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + ufield = upd_get_nth_field(update, 2); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork2, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + btr_pcur_close(&pcur); + /*-------------------------------------*/ + /* INSERT INTO 'ORDERLINE' */ + +/* printf("Trx %lu %lu starts, thr %lu\n", + ut_dulint_get_low(trx->id), + (ulint)trx, + *((ulint*)arg)); */ + + dtuple_gen_test_tuple3(row, count * 13 + j, DTUPLE_TEST_FIXED30, buf); + + ins_node_reset(inode); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork1, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +} + /*-------------------------------------*/ + /* COMMIT */ + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(cfork, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* printf("Trx %lu %lu committed\n", ut_dulint_get_low(trx->id), + (ulint)trx); */ + count++; + + if (count < *((ulint*)arg)) { + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + goto loop; + } + + tm = ut_clock(); + printf("Wall time for TPC-C %lu trxs %lu milliseconds\n", + count, tm - oldtm); + + btr_search_index_print_info(index); + btr_search_index_print_info(dict_table_get_first_index(table)); + +/* mem_print_info(); */ + /*-------------------------------------*/ +/* dict_table_print_by_name("TS_TABLE2"); + dict_table_print_by_name("TS_TABLE3"); */ + + return(0); +} + +/********************************************************************* +Init for purge test. */ + +ulint +test10_1( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint thr_no; + + thr_no = *((ulint*)arg); + + printf("-------------------------------------------------\n"); + printf("TEST 10.1. PURGE INIT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 200; i++) { + + dtuple_gen_test_tuple3(row, i * 100 + thr_no, + DTUPLE_TEST_FIXED30, buf); + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_2( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[1000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.2. PURGE TEST UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(2, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + tuple_no = i; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + dfield_set_data(&(ufield->new_val), dfield_get_data( + dtuple_get_nth_field(entry, 0)), + dfield_get_len( + dtuple_get_nth_field(entry, 0))); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table); + + rnd += 98326761; + + dfield_set_data(&(ufield->new_val), buf2, rnd % 200); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + fsp_validate(0); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + count++; + + if (count < 1) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_2_r( +/*=======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[1000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.2. PURGE TEST UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(2, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + tuple_no = i; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + dfield_set_data(&(ufield->new_val), dfield_get_data( + dtuple_get_nth_field(entry, 0)), + dfield_get_len( + dtuple_get_nth_field(entry, 0))); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table); + + rnd += 98326761; + + dfield_set_data(&(ufield->new_val), buf2, rnd % 2000); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + fsp_validate(0); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + + mem_pool_print_info(mem_comm_pool); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(2000000); + + count++; + + if (count < 1) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_3( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + btr_pcur_t pcur; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + del_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.3. PURGE TEST DELETES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + node = del_node_create(fork, thr, table, &pcur, heap); + thr->child = node; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + rnd = i; + tuple_no = rnd; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu delete markings %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_5( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + btr_pcur_t pcur; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + del_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.5. PURGE TEST UNCOMMITTED DELETES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + node = del_node_create(fork, thr, table, &pcur, heap); + thr->child = node; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 50; i++) { + + rnd = i; + tuple_no = rnd % 100; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu delete markings %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + return(0); +} + +/********************************************************************* +Multithreaded test for purge. */ + +ulint +test10mt( +/*=====*/ + void* arg) +{ + ulint i; + ulint thr_no; + + thr_no = *((ulint*)arg); + + printf("Thread %lu starts purge test\n", thr_no); + + for (i = 0; i < 2; i++) { + test10_1(arg); + + sync_print(); + + fsp_validate(0); + + test10_2_r(arg); + sync_print(); + + test10_2(arg); + sync_print(); + + lock_validate(); + + test10_3(arg); + sync_print(); + } + + printf("Thread %lu ends purge test\n", thr_no); + + return(0); +} + +/********************************************************************* +Purge test. */ + +ulint +test10_4( +/*=====*/ + void* arg) +{ + ulint i; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 10.4. PURGE TEST\n"); + + for (i = 0; i < 30; i++) { + trx_purge(); + + printf("%lu pages purged\n", purge_sys->n_pages_handled); + + os_thread_sleep(5000000); + } + +/* dict_table_print_by_name("TS_TABLE1"); */ + + return(0); +} + +/********************************************************************* +This thread is used to test insert buffer merge. */ + +ulint +test_ibuf_merge( +/*============*/ + void* arg) +{ + ulint sum_sizes; + ulint volume; + + ut_ad(arg); + + printf("Starting ibuf merge\n"); + + sum_sizes = 0; + volume = 1; + + while (volume) { + volume = ibuf_contract(FALSE); + + sum_sizes += volume; + } + + printf("Ibuf merged %lu bytes\n", sum_sizes); + + os_thread_sleep(5000000); + + return(0); +} + +/********************************************************************* +This thread is used to measure contention of latches. */ + +ulint +test_measure_cont( +/*==============*/ + void* arg) +{ + ulint i, j; + ulint count; + + ut_ad(arg); + + printf("Starting contention measurement\n"); + + for (i = 0; i < 1000; i++) { + count = 0; + + for (j = 0; j < 100; j++) { + + os_thread_sleep(10000); + + if ((&(buf_pool->mutex))->lock_word) { + + count++; + } + } + + printf("Mutex reserved %lu of %lu peeks\n", count, j); + } + + return(0); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + os_thread_id_t id[10]; + ulint n1000[10]; + ulint i; + ulint n5000 = 500; + ulint n2; + +/* buf_debug_prints = TRUE; */ + log_do_write = FALSE; + btr_search_use_hash = FALSE; + + srv_boot("initfile"); + os_aio_init(576, 9, 100); + fil_init(25); + buf_pool_init(POOL_SIZE, POOL_SIZE); + fsp_init(); + log_init(); + lock_sys_create(1024); + + create_files(); + + init_spaces(); + + sess_sys_init_at_db_start(); + + trx_sys_create(); + + dict_create(); + +/* os_thread_sleep(500000); */ + + oldtm = ut_clock(); + + ut_rnd_set_seed(19); + + test1(NULL); + test1_5(NULL); + test1_6(NULL); + test1_7(NULL); + +/* for (i = 0; i < 2; i++) { + + n1000[i] = i; + id[i] = id[i]; + + os_thread_create(test10mt, n1000 + i, id + i); + } +*/ + i = 4; + + n1000[i] = i; + id[i] = id[i]; + +/* os_thread_create(test10_4, n1000 + i, id + i); */ + + i = 5; + +/* test10mt(&i); + + i = 6; + + test10mt(&i); + + trx_purge(); + printf("%lu pages purged\n", purge_sys->n_pages_handled); + + dict_table_print_by_name("TS_TABLE1"); */ + +/* os_thread_create(test_measure_cont, &n3, id + 0); */ + +/* mem_print_info(); */ + +/* dict_table_print_by_name("TS_TABLE1"); */ + + n2 = 2000; + +/* test2_1(&n2); */ + + sync_print(); + + test9A(&n2); + + sync_print(); + + log_print(); + + test9(&n2); + + log_print(); + + sync_print(); +/* test6(&n2); */ + +/* test2(&n2); */ + +/* test2_2(&n2); */ + +/* mem_print_info(); */ + + for (i = 0; i < 2; i++) { + + n1000[i] = 1000 + 10 * i; + id[i] = id[i]; + +/* os_thread_create(test2mt, n1000 + i, id + i); + os_thread_create(test2_1mt, n1000 + i, id + i); + os_thread_create(test2_2mt, n1000 + i, id + i); */ + } + + n2 = 2000; + +/* test2mt(&n2); */ + +/* buf_print(); + ibuf_print(); + rw_lock_list_print_info(); + mutex_list_print_info(); + + dict_table_print_by_name("TS_TABLE1"); */ + +/* mem_print_info(); */ + + n2 = 1000; + +/* test4_1(); + test4_2(); + + for (i = 0; i < 2; i++) { + n1000[i] = i; + id[i] = id[i]; + os_thread_create(test4mt, n1000 + i, id + i); + } + + n2 = 4; + test4mt(&n2); + test4mt(&n2); + test4_2(); + lock_print_info(); */ + +/* test7(&n2); */ + +/* os_thread_sleep(25000000); */ + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/btr/ts/tsbtrins.c b/innobase/btr/ts/tsbtrins.c new file mode 100644 index 00000000000..85eedd292b1 --- /dev/null +++ b/innobase/btr/ts/tsbtrins.c @@ -0,0 +1,802 @@ +/************************************************************************ +Test for the B-tree + +(c) 1994-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "os0proc.h" +#include "sync0sync.h" +#include "ut0mem.h" +#include "mem0mem.h" +#include "mem0pool.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "os0file.h" +#include "os0thread.h" +#include "fil0fil.h" +#include "fsp0fsp.h" +#include "rem0rec.h" +#include "rem0cmp.h" +#include "mtr0mtr.h" +#include "log0log.h" +#include "page0page.h" +#include "page0cur.h" +#include "trx0trx.h" +#include "dict0boot.h" +#include "trx0sys.h" +#include "dict0crea.h" +#include "btr0btr.h" +#include "btr0pcur.h" +#include "btr0cur.h" +#include "btr0sea.h" +#include "rem0rec.h" +#include "srv0srv.h" +#include "que0que.h" +#include "com0com.h" +#include "usr0sess.h" +#include "lock0lock.h" +#include "trx0roll.h" +#include "trx0purge.h" +#include "row0ins.h" +#include "row0upd.h" +#include "row0row.h" +#include "row0del.h" +#include "lock0lock.h" +#include "ibuf0ibuf.h" + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[10]; + +mutex_t incs_mutex; +ulint incs; + +#define N_SPACES 2 /* must be >= 2 */ +#define N_FILES 1 +#define FILE_SIZE 8096 /* must be > 512 */ +#define POOL_SIZE 1024 +#define IBUF_SIZE 200 +#define COUNTER_OFFSET 1500 + +#define LOOP_SIZE 150 +#define N_THREADS 5 + +#define COUNT 1 + +ulint zero = 0; + +buf_block_t* bl_arr[POOL_SIZE]; + +ulint dummy = 0; + +byte test_buf[8000]; + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + void* mess; + ulint i; + bool ret; + + segment = *((ulint*)arg); + + printf("Io handler thread %lu starts\n", segment); + + for (i = 0;; i++) { + ret = fil_aio_wait(segment, &mess); + ut_a(ret); + + buf_page_io_complete((buf_block_t*)mess); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + + } + + return(0); +} + +/************************************************************************* +Creates the files for the file system test and inserts them to the file +system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k; + char name[20]; + os_thread_t thr[10]; + os_thread_id_t id[10]; + + printf("--------------------------------------------------------\n"); + printf("Create or open database files\n"); + + strcpy(name, "tsfile00"); + + for (k = 0; k < N_SPACES; k++) { + for (i = 0; i < N_FILES; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, + OS_FILE_TABLESPACE, &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, + OS_FILE_TABLESPACE, &ret); + ut_a(ret); + } else { + if (k == 1) { + ut_a(os_file_set_size(files[i], + 8192 * IBUF_SIZE, 0)); + } else { + ut_a(os_file_set_size(files[i], + 8192 * FILE_SIZE, 0)); + } + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k, OS_FILE_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create(name, FILE_SIZE, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK); + + for (i = 0; i < 9; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/************************************************************************ +Inits space headers of spaces 0 and 1. */ + +void +init_spaces(void) +/*=============*/ +{ + mtr_t mtr; + + mtr_start(&mtr); + + fsp_header_init(0, FILE_SIZE * N_FILES, &mtr); + fsp_header_init(1, IBUF_SIZE, &mtr); + + mtr_commit(&mtr); +} + +/********************************************************************* +Test for table creation. */ + +ulint +test1( +/*==*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1. CREATE TABLE WITH 3 COLUMNS AND WITH 3 INDEXES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE1", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND1", 0, + DICT_UNIQUE | DICT_CLUSTERED, 1); + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND2", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND3", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +#ifdef notdefined + /*-------------------------------------*/ + /* CREATE YET ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND4", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +#endif +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_1( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ins_node_t* node; + ulint count = 0; + ulint rnd; + dtuple_t* row; + dict_index_t* index; +/* dict_tree_t* tree; + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; */ + + printf("-------------------------------------------------\n"); + printf("TEST 2.1. MASSIVE ASCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + log_print(); + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 5000 == 0) { + /* ibuf_print(); */ + /* buf_print(); */ + + /* buf_print_io(); */ + /* + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", + i, tm - oldtm); */ + } + + rnd = rnd + 1; + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + log_print(); + +/* dict_table_print_by_name("TS_TABLE1"); */ + +/* ibuf_print(); */ + + index = index; + + index = dict_table_get_first_index(table); + + if (zero) { + btr_search_index_print_info(index); + } + + btr_validate_tree(dict_index_get_tree(index)); + +#ifdef notdefined + index = dict_table_get_next_index(index); + + if (zero) { + btr_search_index_print_info(index); + } + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + +/* btr_search_index_print_info(index); */ + + btr_validate_tree(dict_index_get_tree(index)); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + /* Check inserted entries */ + + btr_search_print_info(); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); +#endif + /*-------------------------------------*/ + /* ROLLBACK */ + +#ifdef notdefined +/* btr_validate_tree(tree); */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_search_print_info(); +#endif + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + /*-------------------------------------*/ + + count++; +/* btr_validate_tree(tree); */ + + if (count < 1) { + goto loop; + } + + mem_heap_free(heap); + + return(0); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + os_thread_id_t id[10]; + ulint n1000[10]; + ulint i; + ulint n5000 = 500; + ulint n2; + +/* buf_debug_prints = TRUE; */ + log_do_write = TRUE; + + srv_boot("initfile"); + os_aio_init(576, 9, 100); + fil_init(25); + buf_pool_init(POOL_SIZE, POOL_SIZE); + fsp_init(); + log_init(); + lock_sys_create(1024); + + create_files(); + + init_spaces(); + + sess_sys_init_at_db_start(); + + trx_sys_create(); + + dict_create(); + +/* os_thread_sleep(500000); */ + + oldtm = ut_clock(); + + ut_rnd_set_seed(19); + + test1(NULL); + +/* for (i = 0; i < 2; i++) { + + n1000[i] = i; + id[i] = id[i]; + + os_thread_create(test10mt, n1000 + i, id + i); + } +*/ + i = 4; + + n1000[i] = i; + id[i] = id[i]; + +/* os_thread_create(test10_4, n1000 + i, id + i); */ + + i = 5; + +/* test10mt(&i); + + i = 6; + + test10mt(&i); + + trx_purge(); + printf("%lu pages purged\n", purge_sys->n_pages_handled); + + dict_table_print_by_name("TS_TABLE1"); */ + +/* os_thread_create(test_measure_cont, &n3, id + 0); */ + +/* mem_print_info(); */ + +/* dict_table_print_by_name("TS_TABLE1"); */ + + log_flush_up_to(ut_dulint_zero); + + os_thread_sleep(500000); + + n2 = 10000; + + test2_1(&n2); + +/* test9A(&n2); + test9(&n2); */ + +/* test6(&n2); */ + +/* test2(&n2); */ + +/* test2_2(&n2); */ + +/* mem_print_info(); */ + + for (i = 0; i < 2; i++) { + + n1000[i] = 1000 + 10 * i; + id[i] = id[i]; + +/* os_thread_create(test2mt, n1000 + i, id + i); + os_thread_create(test2_1mt, n1000 + i, id + i); + os_thread_create(test2_2mt, n1000 + i, id + i); */ + } + + n2 = 2000; + +/* test2mt(&n2); */ + +/* buf_print(); + ibuf_print(); + rw_lock_list_print_info(); + mutex_list_print_info(); + + dict_table_print_by_name("TS_TABLE1"); */ + +/* mem_print_info(); */ + + n2 = 1000; + +/* test4_1(); + test4_2(); + + for (i = 0; i < 2; i++) { + n1000[i] = i; + id[i] = id[i]; + os_thread_create(test4mt, n1000 + i, id + i); + } + + n2 = 4; + test4mt(&n2); + test4mt(&n2); + test4_2(); + lock_print_info(); */ + +/* test7(&n2); */ + +/* os_thread_sleep(25000000); */ + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/btr/ts/tscli.c b/innobase/btr/ts/tscli.c new file mode 100644 index 00000000000..6c42a83cdbe --- /dev/null +++ b/innobase/btr/ts/tscli.c @@ -0,0 +1,3380 @@ +/************************************************************************ +Tests for the client, TPC-C, and TPC-D Query 5 + +(c) 1996-1998 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "univ.i" +#include "ib_odbc.h" +#include "mem0mem.h" +#include "sync0sync.h" +#include "os0thread.h" +#include "os0proc.h" +#include "os0sync.h" +#include "srv0srv.h" + +ulint n_exited = 0; + +/* Disk wait simulation array */ +typedef struct srv_sim_disk_struct srv_sim_disk_t; +struct srv_sim_disk_struct{ + os_event_t event; /* OS event to wait */ + bool event_set;/* TRUE if the event is in the set state */ + bool empty; /* TRUE if this cell not reserved */ +}; + +#define SRV_N_SIM_DISK_ARRAY 150 + +srv_sim_disk_t srv_sim_disk[SRV_N_SIM_DISK_ARRAY]; + +/* Random counter used in disk wait simulation */ +ulint srv_disk_rnd = 982364761; +ulint srv_disk_n_active_threads = 0; + +char cli_srv_endpoint_name[100]; +char cli_user_name[100]; + +ulint n_warehouses = ULINT_MAX; +ulint n_customers_d = ULINT_MAX; +bool is_tpc_d = FALSE; +ulint n_rounds = ULINT_MAX; +ulint n_users = ULINT_MAX; +ulint startdate = 0; +ulint enddate = 0; +bool own_warehouse = FALSE; + +ulint mem_pool_size = ULINT_MAX; + +/********************************************************************* +Test for TPC-C. */ + +ulint +test_init( +/*======*/ + void* arg) +{ + HENV env; + HDBC conn; + RETCODE ret; + HSTMT stat; + HSTMT create_query; + HSTMT populate_query; + char* str; + char* str1; + char* str2; + char* str3; + char* str4; + char* str5; + char* str6; + char* create_str; + char* populate_str; + char* commit_str; + char* new_order_str; + char* payment_str; + char* order_status_str; + char* delivery_str; + char* stock_level_str; + char* consistency_str; + char* query_5_str; + char* print_str; + char* lock_wait_str; + char* join_test_str; + char* test_errors_str; + char* test_group_commit_str; + char* test_single_row_select_str; + char* rollback_str; + char* ibuf_test_str; + SDWORD n_warehouses_buf; + SDWORD n_warehouses_len; + SDWORD n_customers_d_buf; + SDWORD n_customers_d_len; + + UT_NOT_USED(arg); + + /*------------------------------------------------------*/ + + str1 = + +" PROCEDURE CREATE_TABLES () IS" +" BEGIN" +" CREATE TABLE WAREHOUSE (W_ID CHAR, W_NAME CHAR," +" W_STREET_1 CHAR, W_STREET_2 CHAR," +" W_CITY CHAR," +" W_STATE CHAR, W_ZIP CHAR," +" W_TAX INT," +" W_YTD_HIGH INT," +" W_YTD INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX W_IND ON WAREHOUSE (W_ID);" +"" +" CREATE TABLE DISTRICT (D_ID CHAR, D_W_ID CHAR," +" D_NAME CHAR," +" D_STREET_1 CHAR, D_STREET_2 CHAR," +" D_CITY CHAR," +" D_STATE CHAR, D_ZIP CHAR," +" D_TAX INT," +" D_YTD_HIGH INT," +" D_YTD INT," +" D_NEXT_O_ID INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX D_IND ON DISTRICT (D_W_ID, D_ID);" +"" +" CREATE TABLE CUSTOMER (C_ID CHAR, C_D_ID CHAR, C_W_ID CHAR," +" C_FIRST CHAR, C_MIDDLE CHAR," +" C_LAST CHAR," +" C_STREET_1 CHAR, C_STREET_2 CHAR," +" C_CITY CHAR," +" C_STATE CHAR, C_ZIP CHAR," +" C_PHONE CHAR," +" C_SINCE_TIME INT," +" C_SINCE INT," +" C_CREDIT CHAR," +" C_CREDIT_LIM_HIGH INT," +" C_CREDIT_LIM INT," +" C_DISCOUNT INT," +" C_BALANCE_HIGH INT," +" C_BALANCE INT," +" C_YTD_PAYMENT_HIGH INT," +" C_YTD_PAYMENT INT," +" C_PAYMENT_CNT INT," +" C_DELIVERY_CNT INT," +" C_DATA CHAR) /*DOES_NOT_FIT_IN_MEMORY*/;" +"" +" CREATE UNIQUE CLUSTERED INDEX C_IND ON CUSTOMER (C_W_ID, C_D_ID," +" C_ID);" +"" +" CREATE INDEX C_LAST_IND ON CUSTOMER (C_W_ID, C_D_ID, C_LAST," +" C_FIRST);" +"" +" CREATE TABLE HISTORY (H_C_ID CHAR, H_C_D_ID CHAR, H_C_W_ID CHAR," +" H_D_ID CHAR, H_W_ID CHAR," +" H_DATE INT," +" H_AMOUNT INT," +" H_DATA CHAR);" +"" +" CREATE CLUSTERED INDEX H_IND ON HISTORY (H_W_ID);" +"" +" CREATE TABLE NEW_ORDER (NO_O_ID INT," +" NO_D_ID CHAR," +" NO_W_ID CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX NO_IND ON NEW_ORDER (NO_W_ID, NO_D_ID," +" NO_O_ID);" + ; + + str2 = + +" CREATE TABLE ORDERS (O_ID INT, O_D_ID CHAR, O_W_ID CHAR," +" O_C_ID CHAR," +" O_ENTRY_D INT," +" O_CARRIER_ID INT," +" O_OL_CNT INT," +" O_ALL_LOCAL CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX O_IND ON ORDERS (O_W_ID, O_D_ID," +" O_ID);" +" CREATE INDEX O_C_IND ON ORDERS (O_W_ID, O_D_ID, O_C_ID);" +"" +" CREATE TABLE ORDER_LINE (OL_O_ID INT, OL_D_ID CHAR, OL_W_ID CHAR," +" OL_NUMBER CHAR," +" OL_I_ID CHAR," +" OL_SUPPLY_W_ID CHAR," +" OL_DELIVERY_D INT," +" OL_QUANTITY INT," +" OL_AMOUNT INT," +" OL_DIST_INFO CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX OL_IND ON ORDER_LINE" +" (OL_W_ID, OL_D_ID, OL_O_ID, OL_NUMBER);" +"" +" CREATE TABLE ITEM (I_ID CHAR, I_IM_ID CHAR, I_NAME CHAR," +" I_PRICE INT," +" I_DATA CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX I_IND ON ITEM (I_ID);" +"" +" CREATE TABLE STOCK (S_I_ID CHAR," +" S_W_ID CHAR," +" S_QUANTITY INT," +" S_DIST_01 CHAR," +" S_DIST_02 CHAR," +" S_DIST_03 CHAR," +" S_DIST_04 CHAR," +" S_DIST_05 CHAR," +" S_DIST_06 CHAR," +" S_DIST_07 CHAR," +" S_DIST_08 CHAR," +" S_DIST_09 CHAR," +" S_DIST_10 CHAR," +" S_YTD INT," +" S_ORDER_CNT INT," +" S_REMOTE_CNT INT," +" S_DATA CHAR) /*DOES_NOT_FIT_IN_MEMORY*/;" +"" +" CREATE UNIQUE CLUSTERED INDEX S_IND ON STOCK (S_W_ID, S_I_ID);" +"" +"" +" CREATE TABLE REGION (R_REGIONKEY INT, R_NAME CHAR, R_COMMENT CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX R_IND ON REGION (R_REGIONKEY);" +"" +" CREATE TABLE NATION (N_NATIONKEY INT, N_NAME CHAR, N_REGIONKEY INT," +" N_COMMENT CHAR);" +" CREATE UNIQUE CLUSTERED INDEX N_IND ON NATION (N_NATIONKEY);" +"" +" CREATE TABLE NATION_2 (N2_NATIONKEY INT, N2_NAME CHAR," +" N2_REGIONKEY INT, N2_COMMENT CHAR);" +" CREATE UNIQUE CLUSTERED INDEX N2_IND ON NATION_2 (N2_NAME);" +"" +" CREATE TABLE SUPPLIER (S_SUPPKEY INT, S_NAME CHAR, S_ADDRESS CHAR," +" S_NATIONKEY INT, S_PHONE CHAR," +" S_ACCTBAL INT, S_COMMENT CHAR);" +" CREATE UNIQUE CLUSTERED INDEX SU_IND ON SUPPLIER (S_SUPPKEY);" +"" +" CREATE TABLE CUSTOMER_D (C_CUSTKEY INT, C_NAME CHAR, C_ADDRESS CHAR," +" C_NATIONKEY INT, C_PHONE CHAR," +" C_ACCTBAL INT, C_MKTSEGMENT CHAR," +" C_COMMENT CHAR);" +" CREATE UNIQUE CLUSTERED INDEX CU_IND ON CUSTOMER_D (C_CUSTKEY);" +"" +" CREATE TABLE ORDERS_D (O_ORDERKEY INT, O_CUSTKEY INT," +" O_ORDERSTATUS CHAR, O_TOTALPRICE INT," +" O_ORDERDATE INT," +" O_ORDERPRIORITY CHAR," +" O_CLERK CHAR, O_SHIPPRIORITY INT," +" O_COMMENT CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX OR_IND ON ORDERS_D (O_ORDERKEY);" +"" +" CREATE INDEX OR_D_IND ON ORDERS_D (O_ORDERDATE, O_ORDERKEY," +" O_CUSTKEY);" +"" +" CREATE TABLE LINEITEM (L_ORDERKEY INT, L_PARTKEY INT, L_SUPPKEY INT," +" L_LINENUMBER INT, L_QUANTITY INT," +" L_EXTENDEDPRICE INT," +" L_DISCOUNT INT, L_TAX INT," +" L_RETURNFLAG CHAR," +" L_LINESTATUS CHAR," +" L_SHIPDATE INT, L_COMMITDATE INT," +" L_RECEIPTDATE INT," +" L_SHIPINSTRUCT CHAR," +" L_SHIPMODE CHAR, L_COMMENT CHAR);" +"" +" CREATE UNIQUE CLUSTERED INDEX L_IND ON LINEITEM (L_ORDERKEY," +" L_LINENUMBER);" +"" +" CREATE TABLE ACCOUNTA (A_NUM INT, A_BAL INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX ACCOUNTA_IND ON ACCOUNTA (A_NUM);" +"" +" CREATE TABLE TELLERA (T_NUM INT, T_BAL INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX TELLERA_IND ON TELLERA (T_NUM);" +"" +" CREATE TABLE BRANCHA (B_NUM INT, B_BAL INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX BRANCHA_IND ON BRANCHA (B_NUM);" +"" +" CREATE TABLE HISTORYA (H_NUM INT, H_TEXT CHAR);" +"" +" CREATE CLUSTERED INDEX HISTORYA_IND ON HISTORYA (H_NUM);" +"" +" CREATE TABLE JTEST1 (JT1_A INT, JT1_B INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX JT_IND1 ON JTEST1 (JT1_A);" +"" +" CREATE TABLE JTEST2 (JT2_A INT, JT2_B INT);" +"" +" CREATE UNIQUE CLUSTERED INDEX JT_IND2 ON JTEST2 (JT2_A);" +"" +" CREATE TABLE IBUF_TEST (IB_A INT, IB_B CHAR) DOES_NOT_FIT_IN_MEMORY;" +"" +" CREATE UNIQUE CLUSTERED INDEX IBUF_IND ON IBUF_TEST (IB_A);" +" END;" + ; + + create_str = ut_str_catenate(str1, str2); + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE POPULATE_TABLES (n_warehouses IN INT, n_customers_d" +" IN INT) IS" +"" +" i INT;" +" j INT;" +" k INT;" +" t INT;" +" string CHAR;" +" rnd1 INT;" +" rnd2 INT;" +" rnd INT;" +" n_items INT;" +" n_districts INT;" +" n_customers INT;" +"" +" BEGIN" +"" +"/**********************************************************/" +" PRINTF('Starting Mikko-test');" +"" +" FOR i IN 1 .. 5 LOOP" +" INSERT INTO IBUF_TEST VALUES (i, 'Mikko');" +" END LOOP;" +"" +" /* PRINTF('Printing rows from Mikko-test:');" +"" +" ROW_PRINTF SELECT * FROM IBUF_TEST; */" +"" +" SELECT SUM(IB_A) INTO t FROM IBUF_TEST;" +"" +" PRINTF('Sum of 1 to ', i, ' is ', t);" +" ASSERT(t = (i * (i + 1)) / 2);" +"" +" ROLLBACK WORK;" +"" +" PRINTF('Printing rows from Mikko-test after rollback:');" +"" +" ROW_PRINTF SELECT * FROM IBUF_TEST;" +"" +"/**********************************************************/" +" FOR i IN 0 .. 100 LOOP" +" INSERT INTO ACCOUNTA VALUES (i, i);" +" INSERT INTO TELLERA VALUES (i, i);" +" INSERT INTO BRANCHA VALUES (i, i);" +" INSERT INTO HISTORYA VALUES (i, '12345678901234567890');" +" END LOOP;" +"" +" COMMIT WORK;" +"/**********************************************************/" +"/* PRINTF('Populating ibuf test tables');" +" FOR i IN 1 .. 1000 LOOP" +" INSERT INTO IBUF_TEST VALUES (i, RND_STR(RND(1, 2000)));" +" END LOOP;" +" PRINTF('Ibuf test tables populated');" +" COMMIT WORK; */" +"" +" n_items := 200;" +" n_districts := 10;" +" n_customers := 20;" +"" +" PRINTF('Starting to populate ITEMs');" +"" +" FOR i IN 1 .. n_items LOOP" +" rnd1 := RND(26, 50);" +" string := RND_STR(rnd1);" +"" +" IF (RND(0, 99) < 10) THEN" +" rnd2 := RND(0, rnd1 - 8);" +" REPLSTR(string, 'ORIGINAL', rnd2, 8);" +" END IF;" +"" +" INSERT INTO ITEM VALUES (TO_BINARY(i, 3)," +" TO_BINARY(RND(1, 10000), 3)," +" RND_STR(RND(14, 24))," +" RND(100, 10000)," +" string);" +" END LOOP;" +" COMMIT WORK;" +"" +" FOR i IN 1 .. n_warehouses LOOP" +" COMMIT WORK;" +" PRINTF('Starting to populate warehouse number ', i);" +" INSERT INTO WAREHOUSE VALUES (TO_BINARY(i, 2)," +" RND_STR(RND(6, 10))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(2)," +" CONCAT(SUBSTR(TO_CHAR(RND(0, 9999))," +" 6, 4)," +" '11111')," +" RND(0, 2000)," +" 0," +" 0);" +" FOR j IN 1 .. n_items LOOP" +"" +" rnd1 := RND(26, 50);" +" string := RND_STR(rnd1);" +"" +" IF (RND(0, 99) < 10) THEN" +" rnd2 := RND(0, rnd1 - 8);" +" REPLSTR(string, 'ORIGINAL', rnd2, 8);" +" END IF; " +"" +" INSERT INTO STOCK VALUES (TO_BINARY(j, 3)," +" TO_BINARY(i, 2)," +" 91," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" RND_STR(24)," +" 0, 0, 0," +" string);" +" END LOOP;" + ; + + str2 = +" FOR j IN 1 .. n_districts LOOP" +"" +" /* PRINTF('Starting to populate district number ', j); */" +" INSERT INTO DISTRICT VALUES (TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" RND_STR(RND(6, 10))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(2)," +" CONCAT(SUBSTR(" +" TO_CHAR(RND(0, 9999))," +" 6, 4)," +" '11111')," +" RND(0, 2000)," +" 0," +" 0," +" 3001);" +"" +" FOR k IN 1 .. n_customers LOOP" +"" +" string := 'GC';" +"" +" IF (RND(0, 99) < 10) THEN" +" string := 'BC';" +" END IF;" +" " +" INSERT INTO CUSTOMER VALUES (" +" TO_BINARY(k, 3)," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" RND_STR(RND(8, 16))," +" 'OE'," +" CONCAT('NAME'," +" TO_CHAR(k / 3))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(RND(10, 20))," +" RND_STR(2)," +" CONCAT(SUBSTR(" +" TO_CHAR(RND(0, 9999))," +" 6, 4)," +" '11111')," +" RND_STR(16)," +" SYSDATE(), 0," +" string," +" 0, 5000000," +" RND(0, 5000)," +" 0, 0, 0, 0, 0, 0," +" RND_STR(RND(300, 500)));" + ; + + str3 = +" INSERT INTO HISTORY VALUES (" +" TO_BINARY(k, 3)," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" SYSDATE()," +" 1000," +" RND_STR(RND(12, 24)));" +"" +" rnd1 := RND(5, 15);" +"" +" INSERT INTO ORDERS VALUES (" +" k," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" TO_BINARY(k, 3)," +" SYSDATE()," +" RND(1, 10)," +" rnd1," +" '1');" +"" +" FOR t IN 1 .. rnd1 LOOP" +" INSERT INTO ORDER_LINE VALUES (" +" k," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2)," +" TO_BINARY(t, 1)," +" TO_BINARY(" +" RND(1, n_items)," +" 3)," +" TO_BINARY(i, 2)," +" NULL," +" 91," +" RND(0, 9999)," +" RND_STR(24));" +" END LOOP;" +" END LOOP;" +" " +" FOR k IN 1 /* + (2 * n_customers) / 3 */" +" .. n_customers LOOP" +" " +" INSERT INTO NEW_ORDER VALUES (" +" k," +" TO_BINARY(j + 47, 1)," +" TO_BINARY(i, 2));" +" END LOOP;" +" END LOOP;" +" END LOOP;" +"" +" COMMIT WORK;" +"" +" PRINTF('Populating TPC-D tables');" +"" +" FOR i IN 0 .. 4 LOOP" +" /* We set the last columns to a long character string, to" +" reduce latch contention on region and nation database pages." +" A similar effect could be achieved by setting the page" +" fillfactor in these tables low. */" +"" +" INSERT INTO REGION VALUES (i, CONCAT('Region', TO_CHAR(i)," +" ' ')," +" RND_STR(1500 + RND(1, 152)));" +" FOR j IN i * 5 .. i * 5 + 4 LOOP" +" INSERT INTO NATION VALUES (j," +" CONCAT('Nation', TO_CHAR(j)," +" ' ')," +" i, RND_STR(1500 + RND(1, 152)));" +" INSERT INTO NATION_2 VALUES (j," +" CONCAT('Nation', TO_CHAR(j)," +" ' ')," +" i, RND_STR(1500 + RND(1, 152)));" +" END LOOP;" +" END LOOP;" +"" +" COMMIT WORK;" +"" +" FOR i IN 0 .. n_customers_d / 15 LOOP" +" INSERT INTO SUPPLIER VALUES (i," +" CONCAT('Supplier', TO_CHAR(i))," +" RND_STR(RND(20, 30))," +" RND(0, 24)," +" RND_STR(15)," +" RND(1, 1000)," +" RND_STR(RND(40, 80)));" +" END LOOP;" +"" +" COMMIT WORK;" +"" +" FOR i IN 0 .. n_customers_d - 1 LOOP" +" IF ((i / 100) * 100 = i) THEN" +" COMMIT WORK;" +" PRINTF('Populating customer ', i);" +" END IF;" +"" +" INSERT INTO CUSTOMER_D VALUES (i," +" CONCAT('Customer', TO_CHAR(i))," +" RND_STR(RND(20, 30))," +" RND(0, 24)," +" RND_STR(15)," +" RND(1, 1000)," +" RND_STR(10)," +" RND_STR(RND(50, 100)));" +"" +" FOR j IN i * 10 .. i * 10 + 9 LOOP" +"" +" rnd := (j * 2400) / (10 * n_customers_d);" +"" +" INSERT INTO ORDERS_D VALUES (j," +" 3 * RND(0, (n_customers_d / 3) - 1)" +" + RND(1, 2)," +" 'F', 1000," +" rnd," +" RND_STR(10)," +" CONCAT('Clerk', TO_CHAR(RND(0, 1000)))," +" 0, RND_STR(RND(3, 7)));" +"" +" FOR k IN 0 .. RND(0, 6) LOOP" +" INSERT INTO LINEITEM VALUES (j," +" RND(1, 1000)," +" RND(0, n_customers_d / 15)," +" k," +" RND(1, 50)," +" 100," +" 5," +" RND(0, 8)," +" 'N'," +" 'F'," +" rnd + RND(1, 100)," +" rnd + RND(1, 100)," +" rnd + RND(1, 100)," +" RND_STR(1)," +" RND_STR(1)," +" RND_STR(RND(1, 3)));" +" END LOOP;" +" END LOOP;" +"" +" END LOOP;" +"" +" COMMIT WORK;" +" PRINTF('TPC-D tables populated');" +"" +" PRINTF('Populating join test tables');" +" FOR i IN 1 .. 1 LOOP" +" INSERT INTO JTEST1 VALUES (i, i);" +" INSERT INTO JTEST2 VALUES (i, i);" +" END LOOP;" +" PRINTF('Join test tables populated');" +"" +" COMMIT WORK;" +" END;" + ; + + str4 = ut_str_catenate(str1, str2); + populate_str = ut_str_catenate(str4, str3); + + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE PRINT_TABLES () IS" +" i INT;" +" BEGIN" +"" +" /* PRINTF('Printing ITEM table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM ITEM;" +"" +" PRINTF('Printing WAREHOUSE table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM WAREHOUSE;" +"" +" PRINTF('Printing STOCK table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM STOCK;" +"" +" PRINTF('Printing DISTRICT table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM DISTRICT;" +"" +" PRINTF('Printing CUSTOMER table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM CUSTOMER;" +"" +" PRINTF('Printing HISTORY table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM HISTORY;" +"" +" PRINTF('Printing ORDERS table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM ORDERS;" +"" +" PRINTF('Printing ORDER_LINE table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM ORDER_LINE" +" WHERE OL_O_ID >= 3000; */" +"" +" PRINTF('Printing NEW_ORDER table:');" +"" +" ROW_PRINTF" +" SELECT *" +" FROM NEW_ORDER;" +"" +" COMMIT WORK;" +" END;" + ; + + print_str = str; + /*-----------------------------------------------------------*/ + commit_str = + +" PROCEDURE COMMIT_TEST () IS" +" " +" BEGIN" +" COMMIT WORK;" +" END;" + ; + + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE NEW_ORDER (c_w_id IN CHAR," +" c_d_id IN CHAR," +" c_id IN CHAR," +" ol_supply_w_ids IN CHAR," +" ol_i_ids IN CHAR," +" ol_quantities IN CHAR," +" c_last OUT CHAR," +" c_credit OUT CHAR," +" c_discount OUT INT," +" w_tax OUT INT," +" d_tax OUT INT," +" o_ol_count OUT INT," +" o_id OUT INT," +" o_entry_d OUT INT," +" total OUT INT," +" i_names OUT CHAR," +" s_quantities OUT CHAR," +" bg OUT CHAR," +" i_prices OUT CHAR," +" ol_amounts OUT CHAR) IS" +"" +" i INT;" +" j INT;" +" o_all_local CHAR;" +" i_price INT;" +" i_name CHAR;" +" i_data CHAR;" +" s_quantity INT;" +" s_data CHAR;" +" s_dist_01 CHAR;" +" s_dist_02 CHAR;" +" s_dist_03 CHAR;" +" s_dist_04 CHAR;" +" s_dist_05 CHAR;" +" s_dist_06 CHAR;" +" s_dist_07 CHAR;" +" s_dist_08 CHAR;" +" s_dist_09 CHAR;" +" s_dist_10 CHAR;" +" ol_i_id CHAR;" +" ol_quantity INT;" +" ol_amount INT;" +" ol_supply_w_id CHAR;" +" ol_dist_info CHAR;" +"" +" DECLARE CURSOR district_cursor IS" +" SELECT D_NEXT_O_ID, D_TAX" +" FROM DISTRICT" +" WHERE D_ID = c_d_id AND D_W_ID = c_w_id" +" FOR UPDATE;" +"" +" DECLARE CURSOR stock_cursor IS" +" SELECT S_QUANTITY, S_DATA," +" S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04," +" S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08," +" S_DIST_09, S_DIST_10" +" FROM STOCK" +" WHERE S_W_ID = ol_supply_w_id AND S_I_ID = ol_i_id" +" FOR UPDATE;" + ; + str2 = + +" BEGIN" +" FOR j IN 1 .. 1 LOOP" +"" +" /* PRINTF('Warehouse ', BINARY_TO_NUMBER(c_w_id)); */" +" o_all_local := '1';" +" i_names := '12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "1234567890';" +" s_quantities := '12345678901234567890123456789012345678901234567890" + "1234567890';" +" i_prices := '12345678901234567890123456789012345678901234567890" + "1234567890';" +" ol_amounts := '12345678901234567890123456789012345678901234567890" + "1234567890';" +" bg := 'GGGGGGGGGGGGGGG';" +" total := 0;" +"" +" SELECT C_DISCOUNT, C_LAST, C_CREDIT INTO c_discount, c_last, c_credit" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id AND C_ID = c_id;" +"" +" OPEN district_cursor;" +"" +" FETCH district_cursor INTO o_id, d_tax;" +"" +" UPDATE DISTRICT SET D_NEXT_O_ID = o_id + 1" +" WHERE CURRENT OF district_cursor;" +"" +" CLOSE district_cursor;" +"" +"" + ; + str3 = + +" o_ol_count := LENGTH(ol_quantities);" +"" +" /* PRINTF('C-WAREHOUSE id ', BINARY_TO_NUMBER(c_w_id)," +" ' C-district id ', c_d_id," +" ' order id ', o_id, ' linecount ', o_ol_count); */" +"" +" FOR i IN 0 .. (o_ol_count - 1) LOOP" +"" +" ol_i_id := SUBSTR(ol_i_ids, 3 * i, 3);" +" ol_supply_w_id := SUBSTR(ol_supply_w_ids, 2 * i, 2);" +" ol_quantity := BINARY_TO_NUMBER(SUBSTR(ol_quantities, i, 1));" +"" +" /* PRINTF('ol_i_id ', BINARY_TO_NUMBER(ol_i_id)," +" ' ol_supply_w_id ', BINARY_TO_NUMBER(ol_supply_w_id)," +" ' ol_quantity ', ol_quantity); */" +"" +" SELECT I_PRICE, I_NAME, I_DATA INTO i_price, i_name, i_data" +" FROM ITEM" +" WHERE I_ID = ol_i_id" +" CONSISTENT READ;" +"" +" IF (SQL % NOTFOUND) THEN" +" /* PRINTF('Rolling back; item not found: '," +" BINARY_TO_NUMBER(ol_i_id)); */" +" ROLLBACK WORK;" +" o_ol_count := 0;" +"" +" RETURN;" +" END IF;" +"" +" OPEN stock_cursor;" +"" +" FETCH stock_cursor INTO s_quantity, s_data," +" s_dist_01, s_dist_02, s_dist_03," +" s_dist_04, s_dist_05, s_dist_06," +" s_dist_07, s_dist_08, s_dist_09," +" s_dist_10;" +"" +" /* PRINTF('Stock quantity ', s_quantity); */" +"" +" IF (s_quantity >= ol_quantity + 10) THEN" +" s_quantity := s_quantity - ol_quantity;" +" ELSE" +" s_quantity := (s_quantity + 91) - ol_quantity;" +" END IF;" +"" +" UPDATE STOCK SET S_QUANTITY = s_quantity," +" S_YTD = S_YTD + ol_quantity," +" S_ORDER_CNT = S_ORDER_CNT + 1" + " WHERE CURRENT OF stock_cursor;" +"" +" IF (ol_supply_w_id <> c_w_id) THEN" +"" +" o_all_local := '0';" +" PRINTF('Remote order '," +" BINARY_TO_NUMBER(ol_supply_w_id), ' '," +" BINARY_TO_NUMBER(c_w_id));" +"" +" UPDATE STOCK SET S_REMOTE_CNT = S_REMOTE_CNT + 1" +" WHERE CURRENT OF stock_cursor;" +" END IF;" +"" +" CLOSE stock_cursor;" +"" +" IF ((INSTR(i_data, 'ORIGINAL') > 0)" +" OR (INSTR(s_data, 'ORIGINAL') > 0)) THEN" +" REPLSTR(bg, 'B', i, 1);" +" END IF;" +"" +" ol_amount := ol_quantity * i_price;" +"" +" total := total + ol_amount;" + ; + str4 = +" IF (c_d_id = '0') THEN" +" ol_dist_info := s_dist_01;" +" ELSIF (c_d_id = '1') THEN" +" ol_dist_info := s_dist_02;" +" ELSIF (c_d_id = '2') THEN" +" ol_dist_info := s_dist_03;" +" ELSIF (c_d_id = '3') THEN" +" ol_dist_info := s_dist_04;" +" ELSIF (c_d_id = '4') THEN" +" ol_dist_info := s_dist_05;" +" ELSIF (c_d_id = '5') THEN" +" ol_dist_info := s_dist_06;" +" ELSIF (c_d_id = '6') THEN" +" ol_dist_info := s_dist_07;" +" ELSIF (c_d_id = '7') THEN" +" ol_dist_info := s_dist_08;" +" ELSIF (c_d_id = '8') THEN" +" ol_dist_info := s_dist_09;" +" ELSIF (c_d_id = '9') THEN" +" ol_dist_info := s_dist_10;" +" END IF;" +"" +" INSERT INTO ORDER_LINE VALUES (o_id, c_d_id, c_w_id," +" TO_BINARY(i + 1, 1), ol_i_id," +" ol_supply_w_id, NULL, ol_quantity," +" ol_amount, ol_dist_info);" +"" +" REPLSTR(i_names, i_name, i * 24, LENGTH(i_name));" +" REPLSTR(s_quantities, TO_BINARY(s_quantity, 4), i * 4, 4);" +" REPLSTR(i_prices, TO_BINARY(i_price, 4), i * 4, 4);" +" REPLSTR(ol_amounts, TO_BINARY(ol_amount, 4), i * 4, 4);" +"" +" /* PRINTF('i_name ', i_name, ' s_quantity ', s_quantity," +" ' i_price ', i_price, ' ol_amount ', ol_amount); */" +" END LOOP;" +"" +" SELECT W_TAX INTO w_tax" +" FROM WAREHOUSE" +" WHERE W_ID = c_w_id;" +"" +" total := (((total * (10000 + w_tax + d_tax)) / 10000)" +" * (10000 - c_discount)) / 10000;" +"" +" o_entry_d := SYSDATE();" +"" +" INSERT INTO ORDERS VALUES (o_id, c_d_id, c_w_id, c_id, o_entry_d," +" NULL, o_ol_count, o_all_local);" +" INSERT INTO NEW_ORDER VALUES (o_id, c_d_id, c_w_id);" +"" +" /* PRINTF('Inserted order lines:');" +" ROW_PRINTF" +" SELECT * FROM ORDER_LINE WHERE OL_O_ID = o_id AND" +" OL_D_ID = c_d_id" +" AND OL_W_ID = c_w_id; */" +" COMMIT WORK;" +" END LOOP;" +" END;" + ; + + str5 = ut_str_catenate(str1, str2); + str6 = ut_str_catenate(str3, str4); + + new_order_str = ut_str_catenate(str5, str6); + + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE PAYMENT (c_w_id IN CHAR) IS" +"" +" i INT;" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" w_id CHAR;" +" w_street_1 CHAR;" +" w_street_2 CHAR;" +" w_city CHAR;" +" w_state CHAR;" +" w_zip CHAR;" +" w_name CHAR;" +" d_id CHAR;" +" d_street_1 CHAR;" +" d_street_2 CHAR;" +" d_city CHAR;" +" d_state CHAR;" +" d_zip CHAR;" +" d_name CHAR;" +" c_d_id CHAR;" +" c_street_1 CHAR;" +" c_street_2 CHAR;" +" c_city CHAR;" +" c_state CHAR;" +" c_zip CHAR;" +" c_id CHAR;" +" c_last CHAR;" +" c_first CHAR;" +" c_middle CHAR;" +" c_phone CHAR;" +" c_credit CHAR;" +" c_credit_lim INT;" +" c_discount INT;" +" c_balance INT;" +" c_since INT;" +" c_data CHAR;" +" byname INT;" +" namecnt INT;" +" amount INT;" +" h_data CHAR;" +" h_date INT;" +" c_more_data CHAR;" +" more_len INT;" +" data_len INT;" +"" +" DECLARE CURSOR warehouse_cursor IS" +" SELECT W_STREET_1, W_STREET_2, W_CITY, W_STATE, W_ZIP, W_NAME" +" FROM WAREHOUSE" +" WHERE W_ID = w_id" +" FOR UPDATE;" +"" +" DECLARE CURSOR district_cursor IS" +" SELECT D_STREET_1, D_STREET_2, D_CITY, D_STATE, D_ZIP, D_NAME" +" FROM DISTRICT" +" WHERE D_W_ID = w_id AND D_ID = d_id" +" FOR UPDATE;" +"" +" DECLARE CURSOR customer_by_name_cursor IS" +" SELECT C_ID" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_LAST = c_last" +" ORDER BY C_FIRST ASC;" +"" +" DECLARE CURSOR customer_cursor IS" +" SELECT C_FIRST, C_MIDDLE, C_LAST, C_STREET_1, C_STREET_2," +" C_CITY, C_STATE, C_ZIP, C_PHONE, C_CREDIT," +" C_CREDIT_LIM, C_DISCOUNT, C_BALANCE," +" C_SINCE" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_ID = c_id" +" FOR UPDATE;" + ; + + str2 = + +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 20;" +"" +" byname := RND(1, 100);" +" amount := RND(1, 1000);" +" h_date := SYSDATE();" +" w_id := c_w_id;" +" d_id := TO_BINARY(47 + RND(1, n_districts), 1);" +" c_d_id := TO_BINARY(47 + RND(1, n_districts), 1);" +"" +" IF (byname <= 60) THEN" +" c_last := CONCAT('NAME', TO_CHAR(RND(1, n_customers) / 3));" +"" +" SELECT COUNT(*) INTO namecnt" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_LAST = c_last;" +" /* PRINTF('Payment trx: Customer name ', c_last," +" ' namecount ', namecnt); */" +" OPEN customer_by_name_cursor;" +"" +" FOR i IN 1 .. (namecnt + 1) / 2 LOOP" +" FETCH customer_by_name_cursor INTO c_id;" +" END LOOP;" +" /* ASSERT(NOT (customer_by_name_cursor % NOTFOUND)); */" +" " +" CLOSE customer_by_name_cursor;" +" ELSE" +" c_id := TO_BINARY(RND(1, n_customers), 3);" +" END IF;" + + ; + str3 = +"" +" /* PRINTF('Payment for customer ', BINARY_TO_NUMBER(c_w_id), ' '," +" c_d_id, ' ', BINARY_TO_NUMBER(c_id)); */" +" OPEN customer_cursor;" +"" +" FETCH customer_cursor INTO c_first, c_middle, c_last, c_street_1," +" c_street_2, c_city, c_state, c_zip," +" c_phone, c_credit, c_credit_lim," +" c_discount, c_balance, c_since;" +" c_balance := c_balance - amount;" +"" +" OPEN district_cursor;" +"" +" FETCH district_cursor INTO d_street_1, d_street_2, d_city, d_state," +" d_zip, d_name;" +" UPDATE DISTRICT SET D_YTD = D_YTD + amount" +" WHERE CURRENT OF district_cursor;" +"" +" CLOSE district_cursor;" +"" +" OPEN warehouse_cursor;" +"" +" FETCH warehouse_cursor INTO w_street_1, w_street_2, w_city, w_state," +" w_zip, w_name;" +" UPDATE WAREHOUSE SET W_YTD = W_YTD + amount" +" WHERE CURRENT OF warehouse_cursor;" +"" +" CLOSE warehouse_cursor;" +"" +" h_data := CONCAT(w_name, ' ', d_name);" +" " +" IF (c_credit = 'BC') THEN" +" /* PRINTF('Bad customer pays'); */" +"" +" SELECT C_DATA INTO c_data" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_ID = c_id;" +" c_more_data := CONCAT(" +" ' ', TO_CHAR(BINARY_TO_NUMBER(c_id))," +" ' ', c_d_id," +" ' ', TO_CHAR(BINARY_TO_NUMBER(c_w_id))," +" ' ', d_id," +" ' ', TO_CHAR(BINARY_TO_NUMBER(w_id))," +" TO_CHAR(amount)," +" TO_CHAR(h_date)," +" ' ', h_data);" +"" +" more_len := LENGTH(c_more_data);" +" data_len := LENGTH(c_data);" +" " +" IF (more_len + data_len > 500) THEN" +" data_len := 500 - more_len;" +" END IF;" +" " +" c_data := CONCAT(c_more_data, SUBSTR(c_data, 0, data_len));" +" " +" UPDATE CUSTOMER SET C_BALANCE = c_balance," +" C_PAYMENT_CNT = C_PAYMENT_CNT + 1," +" C_YTD_PAYMENT = C_YTD_PAYMENT + amount," +" C_DATA = c_data" +" WHERE CURRENT OF customer_cursor;" +" ELSE" +" UPDATE CUSTOMER SET C_BALANCE = c_balance," +" C_PAYMENT_CNT = C_PAYMENT_CNT + 1," +" C_YTD_PAYMENT = C_YTD_PAYMENT + amount" +" WHERE CURRENT OF customer_cursor;" +" END IF;" +"" +" CLOSE customer_cursor;" +" " +" INSERT INTO HISTORY VALUES (c_d_id, c_w_id, c_id, d_id, w_id," +" h_date, amount, h_data);" +" COMMIT WORK;" +"" +" END;" + + ; + + str4 = ut_str_catenate(str1, str2); + payment_str = ut_str_catenate(str4, str3); + + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE ORDER_STATUS (c_w_id IN CHAR) IS" +"" +" i INT;" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" d_id CHAR;" +" namecnt INT;" +" c_d_id CHAR;" +" c_id CHAR;" +" c_last CHAR;" +" c_first CHAR;" +" c_middle CHAR;" +" c_balance INT;" +" byname INT;" +" o_id INT;" +" o_carrier_id CHAR;" +" o_entry_d INT;" +" ol_i_id CHAR;" +" ol_supply_w_id CHAR;" +" ol_quantity INT;" +" ol_amount INT;" +" ol_delivery_d INT;" +"" +" DECLARE CURSOR orders_cursor IS" +" SELECT O_ID, O_CARRIER_ID, O_ENTRY_D" +" FROM ORDERS" +" WHERE O_W_ID = c_w_id AND O_D_ID = c_d_id" +" AND O_C_ID = c_id" +" ORDER BY O_ID DESC;" +"" +" DECLARE CURSOR order_line_cursor IS" +" SELECT OL_I_ID, OL_SUPPLY_W_ID, OL_QUANTITY, OL_AMOUNT," +" OL_DELIVERY_D" +" FROM ORDER_LINE" +" WHERE OL_W_ID = c_w_id AND OL_D_ID = c_d_id" +" AND OL_O_ID = o_id;" +" DECLARE CURSOR customer_by_name_cursor IS" +" SELECT C_ID" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_LAST = c_last" +" ORDER BY C_FIRST ASC;" +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 20;" +"" +" byname := RND(1, 100);" +"" + ; + + str2 = + +" IF (byname <= 60) THEN" +" d_id := TO_BINARY(47 + RND(1, n_districts), 1); " +"" +" c_d_id := d_id;" +"" +" c_last := CONCAT('NAME', TO_CHAR(RND(1, n_customers) / 3));" +"" +" SELECT COUNT(*) INTO namecnt" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id" +" AND C_LAST = c_last;" +" OPEN customer_by_name_cursor;" +"" +" /* PRINTF('Order status trx: Customer name ', c_last," +" ' namecount ', namecnt); */" +" FOR i IN 1 .. (namecnt + 1) / 2 LOOP" +" FETCH customer_by_name_cursor INTO c_id;" +" END LOOP;" +" /* ASSERT(NOT (customer_by_name_cursor % NOTFOUND)); */" +"" +" CLOSE customer_by_name_cursor;" +" ELSE" +" c_d_id := TO_BINARY(47 + RND(1, n_districts), 1);" +" c_id := TO_BINARY(RND(1, n_customers), 3);" +" END IF;" +"" +" SELECT C_BALANCE, C_FIRST, C_MIDDLE, C_LAST INTO c_balance, c_first," +" c_middle, c_last" +" FROM CUSTOMER" +" WHERE C_W_ID = c_w_id AND C_D_ID = c_d_id AND C_ID = c_id;" +"" +" OPEN orders_cursor;" +"" +" FETCH orders_cursor INTO o_id, o_carrier_id, o_entry_d;" +"" +" IF (orders_cursor % NOTFOUND) THEN" +" PRINTF('Order status trx: customer has no order');" +" CLOSE orders_cursor;" +"" +" COMMIT WORK;" +"" +" RETURN;" +" END IF;" +"" +" CLOSE orders_cursor;" +"" +" OPEN order_line_cursor;" +"" +" FOR i IN 0 .. 15 LOOP" +" FETCH order_line_cursor INTO ol_i_id, ol_supply_w_id," +" ol_quantity, ol_amount," +" ol_delivery_d;" +"" +" IF (order_line_cursor % NOTFOUND) THEN" +" CLOSE order_line_cursor;" +"" +" COMMIT WORK;" +"" +" RETURN;" +" END IF;" +" END LOOP;" +" ASSERT(0 = 1);" +" " +" END;" + ; + + order_status_str = ut_str_catenate(str1, str2); + /*-----------------------------------------------------------*/ + + str1 = + +" PROCEDURE DELIVERY (w_id IN CHAR) IS" +"" +" i INT;" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" d_id CHAR;" +" c_id CHAR;" +" o_id INT;" +" o_carrier_id INT;" +" ol_delivery_d INT;" +" ol_total INT;" +"" +" DECLARE CURSOR new_order_cursor IS" +" SELECT NO_O_ID" +" FROM NEW_ORDER" +" WHERE NO_W_ID = w_id AND NO_D_ID = d_id" +" ORDER BY NO_O_ID ASC;" +"" +" DECLARE CURSOR orders_cursor IS" +" SELECT O_C_ID" +" FROM ORDERS" +" WHERE O_W_ID = w_id AND O_D_ID = d_id" +" AND O_ID = o_id" +" FOR UPDATE;" +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 20;" +"" +" o_carrier_id := RND(1, 10);" +" ol_delivery_d := SYSDATE();" + + ; + + str2 = + +" FOR i IN 1 .. n_districts LOOP" +"" +" d_id := TO_BINARY(47 + i, 1);" +"" +" OPEN new_order_cursor;" +"" +" FETCH new_order_cursor INTO o_id;" +"" +" IF (new_order_cursor % NOTFOUND) THEN" +" /* PRINTF('No order to deliver'); */" +"" +" CLOSE new_order_cursor;" +" ELSE" +" CLOSE new_order_cursor;" +"" +" DELETE FROM NEW_ORDER" +" WHERE NO_W_ID = w_id AND NO_D_ID = d_id" +" AND NO_O_ID = o_id;" +" OPEN orders_cursor;" +"" +" FETCH orders_cursor INTO c_id;" +"" +" UPDATE ORDERS SET O_CARRIER_ID = o_carrier_id" +" WHERE CURRENT OF orders_cursor;" +"" +" CLOSE orders_cursor;" +"" +" UPDATE ORDER_LINE SET OL_DELIVERY_D = ol_delivery_d" +" WHERE OL_W_ID = w_id AND OL_D_ID = d_id" +" AND OL_O_ID = o_id;" +"" +" SELECT SUM(OL_AMOUNT) INTO ol_total" +" FROM ORDER_LINE" +" WHERE OL_W_ID = w_id AND OL_D_ID = d_id" +" AND OL_O_ID = o_id;" +"" +" UPDATE CUSTOMER SET C_BALANCE = C_BALANCE - ol_total" +" WHERE C_W_ID = w_id AND C_D_ID = d_id" +" AND C_ID = c_id;" +" END IF;" +" END LOOP;" +" COMMIT WORK;" +"" +" " +" END;" + ; + + delivery_str = ut_str_catenate(str1, str2); + + /*-----------------------------------------------------------*/ + + str = + +" PROCEDURE STOCK_LEVEL (w_id IN CHAR) IS" +"" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" d_id CHAR;" +" o_id INT;" +" stock_count INT;" +" threshold INT;" +"" +" BEGIN" +"" +" n_items := 200;" +" n_warehouses := 1;" +" n_districts := 10;" +" n_customers := 20;" +"" +" d_id := TO_BINARY(47 + 4, 1);" +"" +" threshold := RND(10, 20);" +"" +" SELECT D_NEXT_O_ID INTO o_id" +" FROM DISTRICT" +" WHERE D_W_ID = w_id AND D_ID = d_id;" +"" +" /* NOTE: COUNT(DISTINCT ...) not implemented yet: if we used a hash" +" table, the DISTINCT operation should take at most 15 % more time */" +"" +" SELECT COUNT(*) INTO stock_count" +" FROM ORDER_LINE, STOCK" +" WHERE OL_W_ID = w_id AND OL_D_ID = d_id" +" AND OL_O_ID >= o_id - 10 AND OL_O_ID < o_id" +" AND S_W_ID = w_id AND S_I_ID = OL_I_ID" +" AND S_QUANTITY < threshold" +" CONSISTENT READ;" +" /* PRINTF(stock_count, ' items under threshold ', threshold); */" +" COMMIT WORK;" +"" +" END;" + ; + + stock_level_str = str; + + /*-----------------------------------------------------------*/ + + str = + +" PROCEDURE TPC_CONSISTENCY () IS" +"" +" n_items INT;" +" n_warehouses INT;" +" n_districts INT;" +" n_customers INT;" +" n_orders INT;" +" n_new_orders INT;" +" n_order_lines INT;" +" n_history INT;" +" sum_order_quant INT;" +" sum_stock_quant INT;" +" n_delivered INT;" +" n INT;" +" n_new_order_lines INT;" +" n_customers_d INT;" +" n_regions INT;" +" n_nations INT;" +" n_suppliers INT;" +" n_orders_d INT;" +" n_lineitems INT;" +"" +" BEGIN" +"" +" PRINTF('TPC-C consistency check begins');" +"" +" SELECT COUNT(*) INTO n_warehouses" +" FROM WAREHOUSE;" +" SELECT COUNT(*) INTO n_items" +" FROM ITEM;" +" SELECT COUNT(*) INTO n_customers" +" FROM CUSTOMER;" +" SELECT COUNT(*) INTO n_districts" +" FROM DISTRICT;" +" SELECT COUNT(*) INTO n_orders" +" FROM ORDERS;" +" SELECT COUNT(*) INTO n_new_orders" +" FROM NEW_ORDER;" +" SELECT COUNT(*) INTO n_order_lines" +" FROM ORDER_LINE;" +" SELECT COUNT(*) INTO n_history" +" FROM HISTORY;" +"" +" PRINTF('N warehouses ', n_warehouses);" +"" +" PRINTF('N items ', n_items, ' : ', n_items / n_warehouses," +" ' per warehouse');" +" PRINTF('N districts ', n_districts, ' : ', n_districts / n_warehouses," +" ' per warehouse');" +" PRINTF('N customers ', n_customers, ' : ', n_customers / n_districts," +" ' per district');" +" PRINTF('N orders ', n_orders, ' : ', n_orders / n_customers," +" ' per customer');" +" PRINTF('N new orders ', n_new_orders, ' : '," +" n_new_orders / n_customers, ' per customer');" +" PRINTF('N order lines ', n_order_lines, ' : '," +" n_order_lines / n_orders, ' per order');" +" PRINTF('N history ', n_history, ' : '," +" n_history / n_customers, ' per customer');" +" SELECT COUNT(*) INTO n_delivered" +" FROM ORDER_LINE" +" WHERE OL_DELIVERY_D < NULL;" +"" +" PRINTF('N delivered order lines ', n_delivered);" +"" +" SELECT COUNT(*) INTO n_new_order_lines" +" FROM NEW_ORDER, ORDER_LINE" +" WHERE NO_O_ID = OL_O_ID AND NO_D_ID = OL_D_ID" +" AND NO_W_ID = OL_W_ID;" +" PRINTF('N new order lines ', n_new_order_lines);" +"" +" SELECT COUNT(*) INTO n" +" FROM NEW_ORDER, ORDER_LINE" +" WHERE NO_O_ID = OL_O_ID AND NO_D_ID = OL_D_ID" +" AND NO_W_ID = OL_W_ID AND OL_DELIVERY_D < NULL;" +" PRINTF('Assertion 1');" +" ASSERT(n = 0);" +"" +" SELECT COUNT(*) INTO n" +" FROM NEW_ORDER, ORDER_LINE" +" WHERE NO_O_ID = OL_O_ID AND NO_D_ID = OL_D_ID" +" AND NO_W_ID = OL_W_ID AND OL_DELIVERY_D = NULL;" +"" +" PRINTF('Assertion 2');" +" ASSERT(n = n_new_order_lines);" +" PRINTF('Assertion 2B');" +" ASSERT(n_delivered + n_new_order_lines = n_order_lines);" +"" +" PRINTF('Assertion 3');" +" /* ASSERT(n_orders <= n_history); */" +" PRINTF('Assertion 4');" +" ASSERT(n_order_lines <= 15 * n_orders);" +" PRINTF('Assertion 5');" +" ASSERT(n_order_lines >= 5 * n_orders);" +" PRINTF('Assertion 6');" +" ASSERT(n_new_orders <= n_orders);" +"" +" SELECT SUM(OL_QUANTITY) INTO sum_order_quant" +" FROM ORDER_LINE;" +" SELECT SUM(S_QUANTITY) INTO sum_stock_quant" +" FROM STOCK;" +" PRINTF('Sum order quant ', sum_order_quant, ' sum stock quant '," +" sum_stock_quant);" +"" +" PRINTF('Assertion 7');" +" ASSERT(((sum_stock_quant + sum_order_quant) / 91) * 91" +" = sum_stock_quant + sum_order_quant);" +" COMMIT WORK;" +" PRINTF('TPC-C consistency check passed');" +"" +" PRINTF('TPC-D consistency check begins');" +"" +" SELECT COUNT(*) INTO n_customers_d" +" FROM CUSTOMER_D" +" CONSISTENT READ;" +" SELECT COUNT(*) INTO n_nations" +" FROM NATION" +" CONSISTENT READ;" +" SELECT COUNT(*) INTO n_regions" +" FROM REGION" +" CONSISTENT READ;" +" SELECT COUNT(*) INTO n_suppliers" +" FROM SUPPLIER" +" CONSISTENT READ;" +" SELECT COUNT(*) INTO n_orders_d" +" FROM ORDERS_D" +" CONSISTENT READ;" +" SELECT COUNT(*) INTO n_lineitems" +" FROM LINEITEM" +" CONSISTENT READ;" +"" +" PRINTF('N customers TPC-D ', n_customers_d);" +"" +" PRINTF('N nations ', n_nations);" +" PRINTF('N regions ', n_regions);" +"" +" PRINTF('N suppliers ', n_suppliers);" +" PRINTF('N orders TPC-D ', n_orders_d);" +"" +" PRINTF('N lineitems ', n_lineitems, ' : '," +" n_lineitems / n_orders_d, ' per order');" +" SELECT COUNT(*) INTO n" +" FROM NATION, NATION_2" +" WHERE N_NAME = N2_NAME" +" CONSISTENT READ;" +"" +" PRINTF('Assertion D1');" +" ASSERT(n = n_nations);" +"" +" SELECT COUNT(*) INTO n" +" FROM NATION, REGION" +" WHERE N_REGIONKEY = R_REGIONKEY" +" CONSISTENT READ;" +"" +" PRINTF('Assertion D2');" +" ASSERT(n = n_nations);" +"" +" SELECT COUNT(*) INTO n" +" FROM ORDERS_D, CUSTOMER_D" +" WHERE O_CUSTKEY = C_CUSTKEY" +" CONSISTENT READ;" +"" +" PRINTF('Assertion D3');" +" ASSERT(n = n_orders_d);" +"" +" SELECT COUNT(*) INTO n" +" FROM LINEITEM, SUPPLIER" +" WHERE L_SUPPKEY = S_SUPPKEY" +" CONSISTENT READ;" +"" +" PRINTF('Assertion D4');" +" ASSERT(n = n_lineitems);" +"" +" SELECT COUNT(*) INTO n" +" FROM ORDERS_D" +" WHERE O_ORDERDATE >= 0" +" AND O_ORDERDATE <= 2500" +" CONSISTENT READ;" +"" +" PRINTF('Assertion D5');" +" ASSERT(n = n_orders_d);" +"" +" COMMIT WORK;" +" PRINTF('TPC-D consistency check passed');" +"" +" END;" + ; + + consistency_str = str; + + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE TPC_D_QUERY_5 (startday IN INT, endday IN INT) IS" +"" +" revenue INT;" +" r_name CHAR;" +"" +" BEGIN" +"" +" r_name := CONCAT('Region', TO_CHAR(3), ' ');" +"" +" /* The last join to NATION_2 corresponds to calculating" +" GROUP BY N_NAME in the original TPC-D query. It should take" +" approximately the same amount of CPU time as GROUP BY. */" +"" +" SELECT SUM((L_EXTENDEDPRICE * (100 - L_DISCOUNT)) / 100)" +" INTO revenue" +" FROM REGION, ORDERS_D, CUSTOMER_D, NATION," +" LINEITEM, SUPPLIER, NATION_2" +" WHERE R_NAME = r_name" +" AND O_ORDERDATE >= startday" +" AND O_ORDERDATE < endday" +" AND O_CUSTKEY = C_CUSTKEY" +" AND C_NATIONKEY = N_NATIONKEY" +" AND N_REGIONKEY = R_REGIONKEY" +" AND O_ORDERKEY = L_ORDERKEY" +" AND L_SUPPKEY = S_SUPPKEY" +" AND S_NATIONKEY = C_NATIONKEY" +" AND N_NAME = N2_NAME" +" CONSISTENT READ;" +"" +" PRINTF('Startdate ', startday, '; enddate ', endday," +" ': revenue ', revenue);" +" COMMIT WORK;" +"" +" END;" + ; + + query_5_str = str; + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE ROLLBACK_QUERY () IS" +"" +" BEGIN" +"" +" ROLLBACK WORK;" +"" +" END;" + ; + + rollback_str = str; + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE TEST_LOCK_WAIT () IS" +"" +" w_id CHAR;" +" BEGIN" +"" +" w_id := TO_BINARY(1, 2);" +" UPDATE WAREHOUSE SET W_YTD = W_YTD + 1 WHERE W_ID = w_id;" +"" +" END;" + ; + + lock_wait_str = str; + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE TEST_IBUF () IS" +"" +" i INT;" +" rnd INT;" +" j INT;" +" found INT;" +"" +" DECLARE CURSOR desc_cursor IS" +" SELECT IB_A" +" FROM IBUF_TEST" +" WHERE IB_A >= rnd AND IB_A < rnd + 50" +" ORDER BY IB_A DESC;" +"" +" BEGIN" +"" +" PRINTF('Ibuf QUERY starts!!!!!!');" +" rnd := RND(1, 1000);" +"" +" FOR i IN 1 .. 50 LOOP" +" INSERT INTO IBUF_TEST VALUES (rnd + i," +" RND_STR(RND(1, 2000)));" +" END LOOP;" +" IF (RND(1, 100) < 30) THEN" +" PRINTF('Ibuf rolling back ---!!!');" +" ROLLBACK WORK;" +" END IF;" +"" +"" +" IF (RND(1, 100) < 101) THEN" +" rnd := RND(1, 1000);" +" DELETE FROM IBUF_TEST WHERE IB_A >= rnd " +" AND IB_A <= rnd + 50;" +" END IF;" +"" +" rnd := RND(1, 1000);" +" SELECT COUNT(*) INTO j" +" FROM IBUF_TEST" +" WHERE IB_A >= rnd AND IB_A < rnd + 50;" +"" +" PRINTF('Count: ', j);" +"" +" rnd := RND(1, 1000);" +" UPDATE IBUF_TEST" +" SET IB_B = RND_STR(RND(1, 2000))" +" WHERE IB_A >= rnd AND IB_A < rnd + 50;" +"" +" OPEN desc_cursor;" +"" +" rnd := RND(1, 1000);" +" found := 1;" +" WHILE (found > 0) LOOP" +"" +" FETCH desc_cursor INTO j;" +"" +" IF (desc_cursor % NOTFOUND) THEN" +" found := 0;" +" END IF;" +" END LOOP;" +"" +" CLOSE desc_cursor;" +"" +" IF (RND(1, 100) < 30) THEN" +" PRINTF('Ibuf rolling back!!!');" +" ROLLBACK WORK;" +" ELSE" +" COMMIT WORK;" +" END IF;" +"" +" PRINTF('Ibuf QUERY ends!!!!!!');" +" END;" + ; + + ibuf_test_str = str; + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE TEST_GROUP_COMMIT (w_id IN CHAR) IS" +"" +" i INT;" +"" +" BEGIN" +"" +" FOR i IN 1 .. 200 LOOP" +" UPDATE WAREHOUSE SET W_YTD = W_YTD + 1 WHERE W_ID = w_id;" +" COMMIT WORK;" +" END LOOP;" +" END;" + ; + + test_group_commit_str = str; + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE TEST_SINGLE_ROW_SELECT (" +" i_id IN CHAR," +" i_name OUT CHAR) IS" +" BEGIN" +" SELECT I_NAME INTO i_name" +" FROM ITEM" +" WHERE I_ID = i_id" +" CONSISTENT READ;" +" END;" + ; + + test_single_row_select_str = str; + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE JOIN_TEST () IS" +"" +" n_rows INT;" +" i INT;" +"" +" BEGIN" +"" +" FOR i IN 0 .. 0 LOOP" +" SELECT COUNT(*) INTO n_rows" +" FROM JTEST1, JTEST2" +" WHERE JT2_A = JT1_B" +" CONSISTENT READ;" +" PRINTF(n_rows);" +"" +" COMMIT WORK;" +" END LOOP;" +"" +" END;" + ; + + join_test_str = str; + + /*-----------------------------------------------------------*/ + str = + +" PROCEDURE TEST_ERRORS (switch IN CHAR) IS" +"" +" count INT;" +" val INT;" +"" +" BEGIN" +"" +" IF (switch = '01') THEN" +" /* Test duplicate key error: run this first */" +" ROW_PRINTF SELECT * FROM JTEST1;" +" PRINTF('To insert first');" +" INSERT INTO JTEST1 VALUES (1, 1);" +" PRINTF('To insert second');" +" INSERT INTO JTEST1 VALUES (2, 2);" +" END IF;" +"" +" IF (switch = '02') THEN" +" /* Test duplicate key error: run this second */" +" ROW_PRINTF SELECT * FROM JTEST1;" +" PRINTF('To insert third');" +" INSERT INTO JTEST1 VALUES (3, 3);" +" ROW_PRINTF SELECT * FROM JTEST1;" +" PRINTF('To insert fourth');" +" INSERT INTO JTEST1 VALUES (1, 1);" +" END IF;" +"" +" IF (switch = '03') THEN" +" /* Test duplicate key error: run this third */" +" ROW_PRINTF SELECT * FROM JTEST1;" +" PRINTF('Testing assert');" +" SELECT COUNT(*) INTO count FROM JTEST1;" +" ASSERT(count = 2);" +" END IF;" +"" +" IF (switch = '04') THEN" +" /* Test duplicate key error: run this fourth */" +" ROW_PRINTF SELECT * FROM JTEST1;" +" PRINTF('Testing update');" +" UPDATE JTEST1 SET JT1_A = 3 WHERE JT1_A = 2;" +" PRINTF('Testing update');" +" UPDATE JTEST1 SET JT1_A = 1 WHERE JT1_A = 3;" +" END IF;" +"" +" IF (switch = '05') THEN" +" /* Test deadlock error: run this fifth in thread 1 */" +" COMMIT WORK;" +" PRINTF('Testing update in thread 1');" +" UPDATE JTEST1 SET JT1_B = 3 WHERE JT1_A = 1;" +" END IF;" +"" +" IF (switch = '06') THEN" +" /* Test deadlock error: run this sixth in thread 2 */" +" PRINTF('Testing update in thread 2');" +" UPDATE JTEST1 SET JT1_B = 10 WHERE JT1_A = 2;" +" PRINTF('Testing update in thread 2');" +" UPDATE JTEST1 SET JT1_B = 11 WHERE JT1_A = 1;" +" PRINTF('Update in thread 2 completed');" +" SELECT JT1_B INTO val FROM JTEST1 WHERE JT1_A = 1;" +" ASSERT(val = 11);" +" SELECT JT1_B INTO val FROM JTEST1 WHERE JT1_A = 2;" +" ASSERT(val = 10);" +" COMMIT WORK;" +" END IF;" +"" +" IF (switch = '07') THEN" +" /* Test deadlock error: run this seventh in thread 1 */" +" PRINTF('Testing update in thread 1: deadlock');" +" UPDATE JTEST1 SET JT1_B = 4 WHERE JT1_A = 2;" +" END IF;" +"" +" IF (switch = '08') THEN" +" /* Test deadlock error: run this eighth in thread 1 */" +" PRINTF('Testing update in thread 1: commit');" +" SELECT JT1_B INTO val FROM JTEST1 WHERE JT1_A = 1;" +" ASSERT(val = 3);" +" COMMIT WORK;" +" END IF;" +"" +" END;" + ; + + test_errors_str = str; + /*-----------------------------------------------------------*/ + ret = SQLAllocEnv(&env); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocConnect(env, &conn); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &create_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &populate_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLConnect(conn, (UCHAR*)cli_srv_endpoint_name, + (SWORD)ut_strlen(cli_srv_endpoint_name), + (UCHAR*)"use21", 5, (UCHAR*)"password", 8); + ut_a(ret == SQL_SUCCESS); + + printf("Connection established\n"); + + /*-----------------------------------------------------------*/ + ret = SQLPrepare(stat, (UCHAR*)create_str, ut_strlen(create_str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + str = "{CREATE_TABLES()}"; + + ret = SQLPrepare(create_query, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(create_query); + + ut_a(ret == SQL_SUCCESS); + + /*-----------------------------------------------------------*/ + ret = SQLPrepare(stat, (UCHAR*)populate_str, ut_strlen(populate_str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)lock_wait_str, + ut_strlen(lock_wait_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)commit_str, + ut_strlen(commit_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)print_str, + ut_strlen(print_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)new_order_str, + ut_strlen(new_order_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)payment_str, + ut_strlen(payment_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)order_status_str, + ut_strlen(order_status_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)delivery_str, + ut_strlen(delivery_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)stock_level_str, + ut_strlen(stock_level_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)query_5_str, + ut_strlen(query_5_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)consistency_str, + ut_strlen(consistency_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)rollback_str, ut_strlen(rollback_str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)join_test_str, + ut_strlen(join_test_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)test_errors_str, + ut_strlen(test_errors_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)test_single_row_select_str, + ut_strlen(test_single_row_select_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)test_group_commit_str, + ut_strlen(test_group_commit_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLPrepare(stat, (UCHAR*)ibuf_test_str, + ut_strlen(ibuf_test_str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(stat); + + ut_a(ret == SQL_SUCCESS); + + str = "{POPULATE_TABLES(?, ?)}"; + + ret = SQLPrepare(populate_query, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(populate_query, 1, SQL_PARAM_INPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&n_warehouses_buf, + 4, &n_warehouses_len); + ut_a(ret == SQL_SUCCESS); + + n_warehouses_buf = n_warehouses; + n_warehouses_len = 4; + + ret = SQLBindParameter(populate_query, 2, SQL_PARAM_INPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&n_customers_d_buf, + 4, &n_customers_d_len); + ut_a(ret == SQL_SUCCESS); + + n_customers_d_buf = n_customers_d; + n_customers_d_len = 4; + + ret = SQLExecute(populate_query); + + ut_a(ret == SQL_SUCCESS); + + /*-----------------------------------------------------------*/ + printf("TPC-C test database initialized\n"); + + return(0); +} + +/********************************************************************* +Iterates an SQL query until it returns SQL_SUCCESS. If it returns other +value, rolls back the trx, prints an error message, and tries again. */ + +void +execute_until_success( +/*==================*/ + HSTMT query, /* in: query */ + HSTMT rollback_query) /* in: trx rollback query to run if error */ +{ + RETCODE ret; + UCHAR sql_state[6]; + SDWORD native_error; + UCHAR error_msg[512]; + SWORD error_msg_max = 512; + SWORD error_msg_len; + + for (;;) { + ret = SQLExecute(query); + + if (ret != SQL_SUCCESS) { + ut_a(ret == SQL_ERROR); + + ret = SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, query, + sql_state, &native_error, error_msg, + error_msg_max, &error_msg_len); + + ut_a(ret == SQL_SUCCESS); + + printf("%s\n", error_msg); + + /* Roll back to release trx locks, and try again */ + + ret = SQLExecute(rollback_query); + ut_a(ret == SQL_SUCCESS); + + os_thread_sleep(ut_rnd_gen_ulint() / 1000); + } else { + + return; + } + } +} + +/********************************************************************* +Test for TPC-C. */ + +ulint +test_client( +/*=========*/ + void* arg) /* in: user name as a null-terminated string */ +{ + ulint n_customers = 20; + ulint n_items = 200; + ulint n_lines; + bool put_invalid_item; + HENV env; + HDBC conn; + RETCODE ret; + HSTMT commit_query; + HSTMT new_order_query; + HSTMT payment_query; + HSTMT order_status_query; + HSTMT delivery_query; + HSTMT stock_level_query; + HSTMT print_query; + HSTMT lock_wait_query; + HSTMT join_test_query; + HSTMT test_group_commit_query; + HSTMT rollback_query; + HSTMT ibuf_query; + ulint tm, oldtm; + char* str; + byte c_w_id_buf[2]; + byte c_d_id_buf[1]; + byte c_id_buf[3]; + byte ol_supply_w_ids_buf[30]; + byte ol_i_ids_buf[45]; + byte ol_quantities_buf[15]; + byte c_last_buf[51]; + byte c_credit_buf[3]; + ulint c_discount_buf; + ulint w_tax_buf; + ulint d_tax_buf; + ulint o_ol_count_buf; + ulint o_id_buf; + ulint o_entry_d_buf; + ulint total_buf; + byte i_names_buf[361]; + byte s_quantities_buf[60]; + byte bg_buf[16]; + byte i_prices_buf[60]; + byte ol_amounts_buf[60]; + SDWORD c_w_id_len; + SDWORD c_d_id_len; + SDWORD c_id_len; + SDWORD ol_supply_w_ids_len; + SDWORD ol_i_ids_len; + SDWORD ol_quantities_len; + SDWORD c_last_len; + SDWORD c_credit_len; + SDWORD c_discount_len; + SDWORD w_tax_len; + SDWORD d_tax_len; + SDWORD o_ol_count_len; + SDWORD o_id_len; + SDWORD o_entry_d_len; + SDWORD total_len; + SDWORD i_names_len; + SDWORD s_quantities_len; + SDWORD bg_len; + SDWORD i_prices_len; + SDWORD ol_amounts_len; + ulint i; + ulint k; + ulint t; + + printf("Client thread %s\n", (UCHAR*)arg); + + ret = SQLAllocEnv(&env); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocConnect(env, &conn); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &new_order_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &payment_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &order_status_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &delivery_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &stock_level_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &print_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &commit_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &lock_wait_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &join_test_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &test_group_commit_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &rollback_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &ibuf_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLConnect(conn, (UCHAR*)cli_srv_endpoint_name, + (SWORD)ut_strlen(cli_srv_endpoint_name), + (UCHAR*)arg, (SWORD)ut_strlen((char*)arg), + (UCHAR*)"password", 8); + ut_a(ret == SQL_SUCCESS); + + printf("Connection established\n"); + + /*-----------------------------------------------------------*/ + str = + "{NEW_ORDER(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," + " ?, ?, ?, ?)}"; + + ret = SQLPrepare(new_order_query, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 1, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, c_w_id_buf, + 2, &c_w_id_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 2, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, c_d_id_buf, + 1, &c_d_id_len); + ut_a(ret == SQL_SUCCESS); + + c_d_id_len = 1; + + ret = SQLBindParameter(new_order_query, 3, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, c_id_buf, + 3, &c_id_len); + ut_a(ret == SQL_SUCCESS); + + c_id_len = 3; + + ret = SQLBindParameter(new_order_query, 4, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, ol_supply_w_ids_buf, + 30, &ol_supply_w_ids_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 5, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, ol_i_ids_buf, + 45, &ol_i_ids_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 6, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, ol_quantities_buf, + 15, &ol_quantities_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 7, SQL_PARAM_OUTPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, c_last_buf, + 50, &c_last_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 8, SQL_PARAM_OUTPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, + (byte*)&c_credit_buf, + 2, &c_credit_len); + ut_a(ret == SQL_SUCCESS); + c_credit_buf[2] = '\0'; + + ret = SQLBindParameter(new_order_query, 9, SQL_PARAM_OUTPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&c_discount_buf, + 4, &c_discount_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 10, SQL_PARAM_OUTPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&w_tax_buf, + 4, &w_tax_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 11, SQL_PARAM_OUTPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&d_tax_buf, + 4, &d_tax_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 12, SQL_PARAM_OUTPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&o_ol_count_buf, + 4, &o_ol_count_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 13, SQL_PARAM_OUTPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&o_id_buf, + 4, &o_id_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 14, SQL_PARAM_OUTPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&o_entry_d_buf, + 4, &o_entry_d_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 15, SQL_PARAM_OUTPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)&total_buf, + 4, &total_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 16, SQL_PARAM_OUTPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, i_names_buf, + 360, &i_names_len); + ut_a(ret == SQL_SUCCESS); + i_names_buf[360] = '\0'; + + ret = SQLBindParameter(new_order_query, 17, SQL_PARAM_OUTPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, s_quantities_buf, + 60, &s_quantities_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 18, SQL_PARAM_OUTPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, bg_buf, + 15, &bg_len); + ut_a(ret == SQL_SUCCESS); + bg_buf[15] = '\0'; + + ret = SQLBindParameter(new_order_query, 19, SQL_PARAM_OUTPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, i_prices_buf, + 60, &i_prices_len); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(new_order_query, 20, SQL_PARAM_OUTPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, ol_amounts_buf, + 60, &ol_amounts_len); + ut_a(ret == SQL_SUCCESS); + + c_w_id_len = 2; + c_w_id_buf[1] = (byte)(2 * atoi((char*)arg + 4)); + c_w_id_buf[0] = (byte)(2 * (atoi((char*)arg + 4) / 256)); + + k = atoi((char*)arg + 4); + + printf("Client thread %lu starts\n", k); + + /*-----------------------------------------------------------*/ + str = "{PAYMENT(?)}"; + + ret = SQLPrepare(payment_query, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(payment_query, 1, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, c_w_id_buf, + 2, &c_w_id_len); + ut_a(ret == SQL_SUCCESS); + + /*-----------------------------------------------------------*/ + str = "{ORDER_STATUS(?)}"; + + ret = SQLPrepare(order_status_query, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(order_status_query, 1, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, c_w_id_buf, + 2, &c_w_id_len); + ut_a(ret == SQL_SUCCESS); + + /*-----------------------------------------------------------*/ + str = "{DELIVERY(?)}"; + + ret = SQLPrepare(delivery_query, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(delivery_query, 1, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, c_w_id_buf, + 2, &c_w_id_len); + ut_a(ret == SQL_SUCCESS); + + /*-----------------------------------------------------------*/ + str = "{STOCK_LEVEL(?)}"; + + ret = SQLPrepare(stock_level_query, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(stock_level_query, 1, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, c_w_id_buf, + 2, &c_w_id_len); + ut_a(ret == SQL_SUCCESS); + + /*-----------------------------------------------------------*/ + str = "{ROLLBACK_QUERY()}"; + + ret = SQLPrepare(rollback_query, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + /*-----------------------------------------------------------*/ + + oldtm = ut_clock(); + + for (i = k; i < k + n_rounds / n_users; i++) { + + /* execute_until_success(ibuf_query, rollback_query); */ + + if (i % 100 == 0) { + printf("User %s round %lu\n", (char*)arg, i); + } + + if (!own_warehouse) { + c_w_id_buf[1] = (byte)ut_rnd_interval(1, n_warehouses); + c_w_id_buf[0] = (byte)(ut_rnd_interval(1, n_warehouses) + / 256); + } + + mach_write_to_1(c_d_id_buf, (ut_rnd_interval(1, 10) + 47)); + mach_write_to_3(c_id_buf, ut_rnd_interval(1, n_customers)); + + n_lines = ut_rnd_interval(5, 15); + + if ((15 * k + i) % 100 == 0) { + put_invalid_item = TRUE; + + /* printf("Will put invalid item\n"); */ + } else { + put_invalid_item = FALSE; + } + + for (t = 0; t < n_lines; t++) { + mach_write_to_3(ol_i_ids_buf + 3 * t, + ut_rnd_interval(1, n_items)); + + if (put_invalid_item && (t + 1 == n_lines)) { + mach_write_to_3(ol_i_ids_buf + 3 * t, + n_items + 1); + } + + mach_write_to_1(ol_quantities_buf + t, + ut_rnd_interval(10, 20)); + ut_memcpy(ol_supply_w_ids_buf + 2 * t, c_w_id_buf, 2); + } + + ol_i_ids_len = 3 * n_lines; + ol_quantities_len = n_lines; + ol_supply_w_ids_len = 2 * n_lines; + + execute_until_success(new_order_query, rollback_query); + + if (put_invalid_item) { + + goto skip_prints; + } +/* + c_last_buf[c_last_len] = '\0'; + + printf( + "C_LAST %s, c_credit %s, c_discount, %lu, w_tax %lu, d_tax %lu\n", + c_last_buf, c_credit_buf, w_tax_buf, d_tax_buf); + + printf("o_ol_count %lu, o_id %lu, o_entry_d %lu, total %lu\n", + o_ol_count_buf, o_id_buf, o_entry_d_buf, + total_buf); + + ut_a(c_credit_len == 2); + ut_a(c_discount_len == 4); + ut_a(i_names_len == 360); + + printf("i_names %s, bg %s\n", i_names_buf, bg_buf); + + for (t = 0; t < n_lines; t++) { + printf("s_quantity %lu, i_price %lu, ol_amount %lu\n", + mach_read_from_4(s_quantities_buf + 4 * t), + mach_read_from_4(i_prices_buf + 4 * t), + mach_read_from_4(ol_amounts_buf + 4 * t)); + } +*/ + skip_prints: + ; + + execute_until_success(payment_query, rollback_query); + + if (i % 10 == 3) { + execute_until_success(order_status_query, + rollback_query); + } + + if ((i % 10 == 6) || (i % 100 == 60)) { + execute_until_success(delivery_query, rollback_query); + } + + if (i % 10 == 9) { + execute_until_success(stock_level_query, + rollback_query); + } + } + + tm = ut_clock(); + + printf("Wall time for %lu loops %lu milliseconds\n", + (i - k), tm - oldtm); + +/* execute_until_success(print_query, rollback_query); */ + + n_exited++; + + printf("Client thread %lu exits as the %luth\n", k, n_exited); + + return(0); +} + +/********************************************************************* +Test for single row select. */ + +ulint +test_single_row_select( +/*===================*/ + void* arg) /* in: user name as a null-terminated string */ +{ + ulint n_items = 200; + HENV env; + HDBC conn; + RETCODE ret; + HSTMT single_row_select_query; + ulint tm, oldtm; + char* str; + byte i_id_buf[3]; + byte i_name_buf[25]; + SDWORD i_id_len; + SDWORD i_name_len; + ulint i; + + ret = SQLAllocEnv(&env); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocConnect(env, &conn); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn, &single_row_select_query); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLConnect(conn, (UCHAR*)cli_srv_endpoint_name, + (SWORD)ut_strlen(cli_srv_endpoint_name), + (UCHAR*)arg, + (SWORD)ut_strlen((char*)arg), + (UCHAR*)"password", 8); + ut_a(ret == SQL_SUCCESS); + + printf("Connection established\n"); + + /*-----------------------------------------------------------*/ + str = + "{TEST_SINGLE_ROW_SELECT(?, ?)}"; + + ret = SQLPrepare(single_row_select_query, (UCHAR*)str, + ut_strlen(str)); + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(single_row_select_query, 1, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, i_id_buf, + 3, &i_id_len); + ut_a(ret == SQL_SUCCESS); + i_id_len = 3; + + ret = SQLBindParameter(single_row_select_query, 2, SQL_PARAM_OUTPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, i_name_buf, + 24, &i_name_len); + ut_a(ret == SQL_SUCCESS); + i_name_buf[24] = '\0'; + + oldtm = ut_clock(); + + for (i = 0; i < 10000; i++) { + + mach_write_to_3(i_id_buf, ut_rnd_interval(1, n_items)); + + ret = SQLExecute(single_row_select_query); + + ut_a(ret == SQL_SUCCESS); + } + + tm = ut_clock(); + + printf("Wall time for %lu single row selects %lu milliseconds\n", + i, tm - oldtm); + return(0); +} + +/********************************************************************* +TPC-D query 5. */ + +ulint +test_tpc_d_client( +/*==============*/ + void* arg) /* in: pointer to an array of startdate and enddate */ +{ + char buf[20]; + HENV env; + HDBC conn1; + RETCODE ret; + HSTMT query5; + HSTMT join_test; + char* str; + SDWORD len1; + SDWORD len2; + ulint i; + ulint tm, oldtm; + + UT_NOT_USED(arg); + + ret = SQLAllocEnv(&env); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocConnect(env, &conn1); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn1, &query5); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn1, &join_test); + + ut_a(ret == SQL_SUCCESS); + + sprintf(buf, "Use2%5lu", *((ulint*)arg)); + + ret = SQLConnect(conn1, (UCHAR*)cli_srv_endpoint_name, + (SWORD)ut_strlen(cli_srv_endpoint_name), + (UCHAR*)buf, + (SWORD)9, (UCHAR*)"password", 8); + ut_a(ret == SQL_SUCCESS); + + printf("Connection established\n"); + + /*-----------------------------------------------------------*/ + str = "{TPC_D_QUERY_5(?, ?)}"; + + ret = SQLPrepare(query5, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(query5, 1, SQL_PARAM_INPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)arg, + 4, &len1); + ut_a(ret == SQL_SUCCESS); + + len1 = 4; + + ret = SQLBindParameter(query5, 2, SQL_PARAM_INPUT, + SQL_C_LONG, SQL_INTEGER, 0, 0, + (byte*)arg + sizeof(ulint), + 4, &len2); + ut_a(ret == SQL_SUCCESS); + + len2 = 4; + + str = "{JOIN_TEST()}"; + + ret = SQLPrepare(join_test, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + for (i = 0; i < n_rounds; i++) { + + oldtm = ut_clock(); + + ret = SQLExecute(query5); + + /* ret = SQLExecute(join_test); */ + + ut_a(ret == SQL_SUCCESS); + + tm = ut_clock(); + + printf("Wall time %lu milliseconds\n", tm - oldtm); + } + + printf("%s exits\n", buf); + + return(0); +} + +/********************************************************************* +Checks consistency of the TPC databases. */ + +ulint +check_tpc_consistency( +/*==================*/ + void* arg) /* in: user name */ +{ + HENV env; + HDBC conn1; + RETCODE ret; + HSTMT consistency_query1; + char* str; + + UT_NOT_USED(arg); + + ret = SQLAllocEnv(&env); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocConnect(env, &conn1); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn1, &consistency_query1); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLConnect(conn1, (UCHAR*)cli_srv_endpoint_name, + (SWORD)ut_strlen(cli_srv_endpoint_name), + (UCHAR*)arg, + (SWORD)ut_strlen((char*)arg), (UCHAR*)"password", 8); + ut_a(ret == SQL_SUCCESS); + + printf("Connection established\n"); + + /*-----------------------------------------------------------*/ + str = "{TPC_CONSISTENCY()}"; + + ret = SQLPrepare(consistency_query1, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLExecute(consistency_query1); + + ut_a(ret == SQL_SUCCESS); + + printf("Consistency checked\n"); + + return(0); +} + +/********************************************************************* +Test for errors. */ + +ulint +test_client_errors2( +/*================*/ + void* arg) /* in: ignored */ +{ + HENV env; + HDBC conn1; + RETCODE ret; + HSTMT error_test_query1; + char* str; + byte buf1[2]; + SDWORD len1; + UCHAR sql_state[6]; + SDWORD native_error; + UCHAR error_msg[512]; + SWORD error_msg_max = 512; + SWORD error_msg_len; + + UT_NOT_USED(arg); + + ret = SQLAllocEnv(&env); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocConnect(env, &conn1); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn1, &error_test_query1); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLConnect(conn1, (UCHAR*)cli_srv_endpoint_name, + (SWORD)ut_strlen(cli_srv_endpoint_name), + (UCHAR*)"conn2", + (SWORD)5, (UCHAR*)"password", 8); + ut_a(ret == SQL_SUCCESS); + + printf("Connection established\n"); + + /*-----------------------------------------------------------*/ + str = "{TEST_ERRORS(?)}"; + + ret = SQLPrepare(error_test_query1, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(error_test_query1, 1, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, buf1, + 2, &len1); + ut_a(ret == SQL_SUCCESS); + + /*-----------------------------------------------------------*/ + + printf("Thread 2 to do update\n"); + + ut_memcpy(buf1, "06", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_SUCCESS); + + printf("Thread 2 has done update\n"); + + ret = SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, error_test_query1, + sql_state, &native_error, error_msg, error_msg_max, + &error_msg_len); + + ut_a(ret == SQL_NO_DATA_FOUND); + + return(0); +} + +/********************************************************************* +Test for errors. */ + +ulint +test_client_errors( +/*===============*/ + void* arg) /* in: ignored */ +{ + HENV env; + HDBC conn1; + RETCODE ret; + HSTMT error_test_query1; + char* str; + byte buf1[2]; + SDWORD len1; + UCHAR sql_state[6]; + SDWORD native_error; + UCHAR error_msg[512]; + SWORD error_msg_max = 512; + SWORD error_msg_len; + os_thread_id_t thread_id; + + UT_NOT_USED(arg); + + ret = SQLAllocEnv(&env); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocConnect(env, &conn1); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLAllocStmt(conn1, &error_test_query1); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLConnect(conn1, (UCHAR*)"innobase", 8, (UCHAR*)"conn1", + (SWORD)5, (UCHAR*)"password", 8); + ut_a(ret == SQL_SUCCESS); + + printf("Connection established\n"); + + /*-----------------------------------------------------------*/ + str = "{TEST_ERRORS(?)}"; + + ret = SQLPrepare(error_test_query1, (UCHAR*)str, ut_strlen(str)); + + ut_a(ret == SQL_SUCCESS); + + ret = SQLBindParameter(error_test_query1, 1, SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, 0, 0, buf1, + 2, &len1); + ut_a(ret == SQL_SUCCESS); + + /*-----------------------------------------------------------*/ + + ut_memcpy(buf1, "01", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_SUCCESS); + + ut_memcpy(buf1, "02", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_ERROR); + + ret = SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, error_test_query1, + sql_state, &native_error, error_msg, error_msg_max, + &error_msg_len); + + ut_a(ret == SQL_SUCCESS); + + printf("%s\n", error_msg); + + ret = SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, error_test_query1, + sql_state, &native_error, error_msg, error_msg_max, + &error_msg_len); + + ut_a(ret == SQL_NO_DATA_FOUND); + + ut_memcpy(buf1, "03", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_SUCCESS); + + ut_memcpy(buf1, "01", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_ERROR); + + ret = SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, error_test_query1, + sql_state, &native_error, error_msg, error_msg_max, + &error_msg_len); + + ut_a(ret == SQL_SUCCESS); + + printf("%s\n", error_msg); + + ut_memcpy(buf1, "03", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_SUCCESS); + + ut_memcpy(buf1, "04", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_ERROR); + + ret = SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, error_test_query1, + sql_state, &native_error, error_msg, error_msg_max, + &error_msg_len); + + ut_a(ret == SQL_SUCCESS); + + printf("%s\n", error_msg); + + ut_memcpy(buf1, "03", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_SUCCESS); + + ut_memcpy(buf1, "05", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_SUCCESS); + + os_thread_create(&test_client_errors2, "user000", &thread_id); + + os_thread_sleep(5000000); + + ut_memcpy(buf1, "07", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_ERROR); + + ret = SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, error_test_query1, + sql_state, &native_error, error_msg, error_msg_max, + &error_msg_len); + + ut_a(ret == SQL_SUCCESS); + + printf("%s\n", error_msg); + + printf("Thread 1 to commit\n"); + + ut_memcpy(buf1, "08", 2); + len1 = 2; + ret = SQLExecute(error_test_query1); + ut_a(ret == SQL_SUCCESS); + + return(0); +} + +/************************************************************************* +Simulates disk waits: if there are at least two threads active, +puts the current thread to wait for an event. If there is just the current +thread active and another thread doing a simulated disk wait, puts the +current thread to wait and releases another thread from wait, otherwise does +nothing */ + +void +srv_simulate_disk_wait(void) +/*========================*/ +{ + os_event_t event; + ulint wait_i; + ulint count; + bool found; + ulint rnd; + ulint i; + ulint j; + + mutex_enter(&kernel_mutex); + + srv_disk_rnd += 98687241; + + count = 0; + found = FALSE; + + for (i = 0; i < SRV_N_SIM_DISK_ARRAY; i++) { + + if (!srv_sim_disk[i].empty) { + + count++; + } + + if (!found && srv_sim_disk[i].empty) { + + srv_sim_disk[i].empty = FALSE; + event = srv_sim_disk[i].event; + + os_event_reset(event); + srv_sim_disk[i].event_set = FALSE; + + wait_i = i; + + found = TRUE; + } + } + + ut_a(found); + + if (srv_disk_n_active_threads == count + 1) { + /* We have to release a thread from the disk wait array */; + + rnd = srv_disk_rnd; + + for (i = rnd; i < SRV_N_SIM_DISK_ARRAY + rnd; i++) { + + j = i % SRV_N_SIM_DISK_ARRAY; + + if (!srv_sim_disk[j].empty + && !srv_sim_disk[j].event_set) { + + srv_sim_disk[j].event_set = TRUE; + os_event_set(srv_sim_disk[j].event); + + break; + } + } + } + + mutex_exit(&kernel_mutex); + + os_event_wait(event); + + mutex_enter(&kernel_mutex); + + srv_sim_disk[wait_i].empty = TRUE; + + mutex_exit(&kernel_mutex); +} + +/************************************************************************* +Releases a thread from the simulated disk wait array if there is any to +release. */ + +void +srv_simulate_disk_wait_release(void) +/*================================*/ +{ + ulint rnd; + ulint i; + ulint j; + + mutex_enter(&kernel_mutex); + + srv_disk_rnd += 98687241; + rnd = srv_disk_rnd; + + for (i = rnd; i < SRV_N_SIM_DISK_ARRAY + rnd; i++) { + + j = i % SRV_N_SIM_DISK_ARRAY; + + if (!srv_sim_disk[j].empty + && !srv_sim_disk[j].event_set) { + + srv_sim_disk[j].event_set = TRUE; + os_event_set(srv_sim_disk[j].event); + + break; + } + } + + mutex_exit(&kernel_mutex); +} + +/********************************************************************* +Test for many threads and disk waits. */ + +ulint +test_disk_waits( +/*============*/ + void* arg) /* in: ignored */ +{ + ulint i; + ulint tm, oldtm; + + UT_NOT_USED(arg); + + n_exited++; + + printf("Client thread starts as the %luth\n", n_exited); + + oldtm = ut_clock(); + + mutex_enter(&kernel_mutex); + srv_disk_n_active_threads++; + mutex_exit(&kernel_mutex); + + for (i = 0; i < 133; i++) { + ut_delay(500); + +/* os_thread_yield(); */ + +/* os_thread_sleep(10000); */ + + srv_simulate_disk_wait(); + } + + mutex_enter(&kernel_mutex); + srv_disk_n_active_threads--; + mutex_exit(&kernel_mutex); + + srv_simulate_disk_wait_release(); + + tm = ut_clock(); + + printf("Wall time for %lu loops %lu milliseconds\n", i, tm - oldtm); + + n_exited++; + + printf("Client thread exits as the %luth\n", n_exited); + + return(0); +} + +/************************************************************************* +Reads a keywords and a values from an initfile. In case of an error, exits +from the process. */ + +void +cli_read_initfile( +/*==============*/ + FILE* initfile) /* in: file pointer */ +{ + char str_buf[10000]; + ulint ulint_val; + + srv_read_init_val(initfile, FALSE, "SRV_ENDPOINT_NAME", str_buf, + &ulint_val); + ut_a(ut_strlen(str_buf) < COM_MAX_ADDR_LEN); + + ut_memcpy(cli_srv_endpoint_name, str_buf, COM_MAX_ADDR_LEN); + + srv_read_init_val(initfile, FALSE, "USER_NAME", str_buf, + &ulint_val); + ut_a(ut_strlen(str_buf) < COM_MAX_ADDR_LEN); + + ut_memcpy(cli_user_name, str_buf, COM_MAX_ADDR_LEN); + + srv_read_init_val(initfile, TRUE, "MEM_POOL_SIZE", str_buf, + &mem_pool_size); + + srv_read_init_val(initfile, TRUE, "N_WAREHOUSES", str_buf, + &n_warehouses); + + srv_read_init_val(initfile, TRUE, "N_CUSTOMERS_D", str_buf, + &n_customers_d); + + srv_read_init_val(initfile, TRUE, "IS_TPC_D", str_buf, + &is_tpc_d); + + srv_read_init_val(initfile, TRUE, "N_ROUNDS", str_buf, + &n_rounds); + + srv_read_init_val(initfile, TRUE, "N_USERS", str_buf, + &n_users); + + srv_read_init_val(initfile, TRUE, "STARTDATE", str_buf, + &startdate); + + srv_read_init_val(initfile, TRUE, "ENDDATE", str_buf, + &enddate); + + srv_read_init_val(initfile, TRUE, "OWN_WAREHOUSE", str_buf, + &own_warehouse); +} + +/************************************************************************* +*/ +void +cli_boot( +/*=====*/ + char* name) /* in: the initialization file name */ +{ + FILE* initfile; + + initfile = fopen(name, "r"); + + if (initfile == NULL) { + printf( + "Error in client booting: could not open initfile whose name is %s!\n", + name); + os_process_exit(1); + } + + cli_read_initfile(initfile); + + fclose(initfile); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + os_thread_t thread_handles[1000]; + os_thread_id_t thread_ids[1000]; + char user_names[1000]; + ulint tm, oldtm; + ulint i; + ulint dates[1000]; + + cli_boot("cli_init"); + + for (i = 1; i <= n_users; i++) { + dates[2 * i] = startdate + + ((enddate - startdate) / n_users) * (i - 1); + dates[2 * i + 1] = startdate + + ((enddate - startdate) / n_users) * i; + } + + sync_init(); + + mem_init(mem_pool_size); + + test_init(NULL); + + check_tpc_consistency("con21"); + +/* test_client_errors(NULL); */ + + os_thread_sleep(4000000); + + printf("Sleep ends\n"); + + oldtm = ut_clock(); + + for (i = 2; i <= n_users; i++) { + if (is_tpc_d) { + thread_handles[i] = os_thread_create(&test_tpc_d_client, + dates + 2 * i, thread_ids + i); + } else { + sprintf(user_names + i * 8, "use2%3lu", i); + + thread_handles[i] = os_thread_create(&test_client, + user_names + i * 8, thread_ids + i); + } + + ut_a(thread_handles[i]); + } + + if (is_tpc_d) { + test_tpc_d_client(dates + 2 * 1); + } else { + test_client("use2 1"); + } + + for (i = 2; i <= n_users; i++) { + os_thread_wait(thread_handles[i]); + + printf("Wait for thread %lu ends\n", i); + } + + tm = ut_clock(); + + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + + os_thread_sleep(4000000); + + printf("Sleep ends\n"); + + test_single_row_select("con99"); + + check_tpc_consistency("con22"); + + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/btr/ts/tsrecv.c b/innobase/btr/ts/tsrecv.c new file mode 100644 index 00000000000..0f30fcd94f1 --- /dev/null +++ b/innobase/btr/ts/tsrecv.c @@ -0,0 +1,4909 @@ +/************************************************************************ +Test for the B-tree + +(c) 1994-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "os0proc.h" +#include "sync0sync.h" +#include "ut0mem.h" +#include "mem0mem.h" +#include "mem0pool.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "os0file.h" +#include "os0thread.h" +#include "fil0fil.h" +#include "fsp0fsp.h" +#include "rem0rec.h" +#include "rem0cmp.h" +#include "mtr0mtr.h" +#include "log0log.h" +#include "log0recv.h" +#include "page0page.h" +#include "page0cur.h" +#include "trx0trx.h" +#include "dict0boot.h" +#include "trx0sys.h" +#include "dict0crea.h" +#include "btr0btr.h" +#include "btr0pcur.h" +#include "btr0cur.h" +#include "btr0sea.h" +#include "rem0rec.h" +#include "srv0srv.h" +#include "que0que.h" +#include "com0com.h" +#include "usr0sess.h" +#include "lock0lock.h" +#include "trx0roll.h" +#include "trx0purge.h" +#include "row0ins.h" +#include "row0upd.h" +#include "row0row.h" +#include "row0del.h" +#include "lock0lock.h" +#include "ibuf0ibuf.h" + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[10]; + +mutex_t incs_mutex; +ulint incs; + +byte bigbuf[1000000]; + +#define N_SPACES 3 /* must be >= 2 */ +#define N_FILES 1 +#define FILE_SIZE 512 /* must be > 512 */ +#define POOL_SIZE 1000 +#define IBUF_SIZE 200 +#define COUNTER_OFFSET 1500 + +#define N_LOG_GROUPS 2 +#define N_LOG_FILES 3 +#define LOG_FILE_SIZE 500 + +#define LOOP_SIZE 150 +#define N_THREADS 5 + +#define COUNT 1 + +ulint zero = 0; + +buf_block_t* bl_arr[POOL_SIZE]; + +ulint dummy = 0; + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + ulint i; + + segment = *((ulint*)arg); + + printf("Io handler thread %lu starts\n", segment); + + for (i = 0;; i++) { + fil_aio_wait(segment); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + + } + + return(0); +} + +/************************************************************************* +Creates or opens the log files. */ + +void +create_log_files(void) +/*==================*/ +{ + bool ret; + ulint i, k; + char name[20]; + + printf("--------------------------------------------------------\n"); + printf("Create or open log files\n"); + + strcpy(name, "logfile00"); + + for (k = 0; k < N_LOG_GROUPS; k++) { + for (i = 0; i < N_LOG_FILES; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_AIO, + &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_AIO, &ret); + ut_a(ret); + } else { + ut_a(os_file_set_size(files[i], + 8192 * LOG_FILE_SIZE, 0)); + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k + 100, FIL_LOG); + } + + ut_a(fil_validate()); + + fil_node_create(name, LOG_FILE_SIZE, k + 100); + } + + fil_space_create(name, k + 200, FIL_LOG); + + log_group_init(k, N_LOG_FILES, LOG_FILE_SIZE * UNIV_PAGE_SIZE, + k + 100, k + 200); + } +} + +/************************************************************************* +Creates the files for the file system test and inserts them to the file +system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k; + char name[20]; + os_thread_t thr[10]; + os_thread_id_t id[10]; + + printf("--------------------------------------------------------\n"); + printf("Create or open database files\n"); + + strcpy(name, "tsfile00"); + + for (k = 0; k < 2 * N_SPACES; k += 2) { + for (i = 0; i < N_FILES; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, + OS_FILE_AIO, &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_AIO, &ret); + ut_a(ret); + } else { + if (k == 1) { + ut_a(os_file_set_size(files[i], + 8192 * IBUF_SIZE, 0)); + } else { + ut_a(os_file_set_size(files[i], + 8192 * FILE_SIZE, 0)); + } + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k, FIL_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create(name, FILE_SIZE, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK); + + for (i = 0; i < 9; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/********************************************************************* +Test for table creation. */ + +ulint +test1( +/*==*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1. CREATE TABLE WITH 3 COLUMNS AND WITH 3 INDEXES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE1", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND1", 0, + DICT_UNIQUE | DICT_CLUSTERED, 1); + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND2", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND3", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +#ifdef notdefined + /*-------------------------------------*/ + /* CREATE YET ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND4", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +#endif +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_5( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.5. CREATE TABLE WITH 3 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE2", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE2", "IND1", 0, + DICT_CLUSTERED | DICT_UNIQUE, 1); + + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_6( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.6. CREATE TABLE WITH 3 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE3", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE3", "IND1", 0, DICT_CLUSTERED, + 2); + dict_mem_index_add_field(index, "COL1", 0); + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_7( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.7. CREATE TABLE WITH 12 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE4", 0, 12); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL4", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL5", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL6", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL7", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL8", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL9", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL10", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL11", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL12", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE4", "IND1", 0, + DICT_CLUSTERED | DICT_UNIQUE, 1); + + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Test for inserts. */ + +ulint +test2( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + dict_index_t* index; +/* ulint size; */ + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2. MASSIVE INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + /* MASSIVE RANDOM INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 7857641) % 200000; + + dtuple_gen_test_tuple3(row, rnd, + DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 1000 == 0) { + printf( + "********************************Inserted %lu rows\n", i); + ibuf_print(); + } + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); +/* + for (i = 0; i < 10; i++) { + size = ibuf_contract(TRUE); + + printf("%lu bytes will be contracted\n", size); + + os_thread_sleep(1000000); + } +*/ + index = dict_table_get_next_index(dict_table_get_first_index(table)); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + index = dict_table_get_next_index(index); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + btr_search_print_info(); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 7857641) % 200000; + dtuple_gen_search_tuple3(entry, rnd, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); + +/* btr_print_tree(tree, 5); */ + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + btr_validate_tree(tree); + +/* btr_search_print_info(); + dict_table_print_by_name("TS_TABLE1"); */ + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_1( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ins_node_t* node; + ulint count = 0; + ulint rnd; + dtuple_t* row; +/* dict_tree_t* tree; + dict_index_t* index; + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; */ + + printf("-------------------------------------------------\n"); + printf("TEST 2.1. MASSIVE ASCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + rnd = 0; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND3500, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 5000 == 0) { + /* ibuf_print(); */ + /* buf_print(); */ + + /* buf_print_io(); */ + + tm = ut_clock(); + /* + printf("Wall time for %lu inserts %lu milliseconds\n", + i, tm - oldtm); */ + } + + rnd = rnd + 1; + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + +#ifdef notdefined +/* dict_table_print_by_name("TS_TABLE1"); */ + + ibuf_print(); + + index = dict_table_get_first_index(table); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + /* Check inserted entries */ + + btr_search_print_info(); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); +#endif +#ifdef notdefined + /*-------------------------------------*/ + /* ROLLBACK */ + +/* btr_validate_tree(tree); */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_search_print_info(); + +#endif + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + /*-------------------------------------*/ + + count++; +/* btr_validate_tree(tree); */ + + if (count < 5) { + goto loop; + } + + mem_heap_free(heap); + + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_2( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + btr_pcur_t pcur; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2.2. MASSIVE DESCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = *((ulint*)arg) + 1; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd - 1) % 200000; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 1000 == 0) { +/* printf( + "********************************Inserted %lu rows\n", i); + ibuf_print(); */ + } + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /* Check inserted entries */ + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i + 1, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_validate_tree(tree); +/* dict_table_print_by_name("TS_TABLE1"); */ + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + + btr_validate_tree(tree); + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Multithreaded test for random inserts. */ + +ulint +test2mt( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2MT. MULTITHREADED RANDOM INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + rnd = 78675; +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + if (i % 100 == 0) { +/* buf_print(); */ +/* ibuf_print(); */ + } + + rnd = (rnd + 7857641) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for multithreaded sequential inserts. */ + +ulint +test2_1mt( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2.1MT. MULTITHREADED ASCENDING INSERT\n"); + + rnd = 8757677; + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + rnd += 98667501; + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 1) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for multithreaded sequential inserts. */ + +ulint +test2_2mt( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2.2MT. MULTITHREADED DESCENDING INSERT\n"); + + rnd = 87677; + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + rnd += 78667; + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd - 1) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + mem_print_info(); + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for updates. */ + +ulint +test3( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + byte* ptr; + ulint len; + ulint err; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 3. UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 3; i++) { + dtuple_gen_test_tuple3(row, i, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + dict_table_print_by_name("TS_TABLE1"); + /*-------------------------------------*/ + /* UPDATE ROWS */ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + dtuple_gen_test_tuple3(row, 1, DTUPLE_TEST_RND30, buf); + + entry = dtuple_create(heap, 2); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + dfield_copy(dtuple_get_nth_field(entry, 1), + dtuple_get_nth_field(row, 1)); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), "updated field", 14); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + mtr_start(&mtr); + + ut_a(btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr)); + + ptr = rec_get_nth_field(btr_pcur_get_rec(&pcur), 5, &len); + + ut_a(ut_memcmp(ptr, "updated field", 14) == 0); + + btr_pcur_commit(&pcur); + + dict_table_print_by_name("TS_TABLE1"); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + dfield_set_data(&(ufield->new_val), "31415926", 9); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + dict_table_print_by_name("TS_TABLE1"); + /*-------------------------------------*/ + /* ROLLBACK */ +#ifdef notdefined + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ +#endif + dict_table_print_by_name("TS_TABLE1"); + count++; + + if (count < 1) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Init for update test. */ + +ulint +test4_1(void) +/*=========*/ +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + + printf("-------------------------------------------------\n"); + printf("TEST 4.1. UPDATE INIT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 200; i++) { + + dtuple_gen_test_tuple3(row, i, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + dict_table_print_by_name("TS_TABLE1"); + + return(0); +} + +/************************************************************************* +Checks that the multithreaded update test has rolled back its updates. */ + +void +test4_2(void) +/*=========*/ +{ + dtuple_t* entry; + mem_heap_t* heap; + mem_heap_t* heap2; + mtr_t mtr; + byte buf[32]; + sess_t* sess; + com_endpoint_t* com_endpoint; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + dtuple_t* row; + btr_pcur_t pcur; + rec_t* rec; + + printf("-------------------------------------------------\n"); + printf("TEST 4.2. CHECK UPDATE RESULT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*------------------------------------------*/ + + table = dict_table_get("TS_TABLE1", trx); + + index = dict_table_get_first_index(table); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < 200; i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + rec = btr_pcur_get_rec(&pcur); + + ut_a(0 == cmp_dtuple_rec(entry, rec)); + + heap2 = mem_heap_create(200); + + row = row_build(ROW_COPY_DATA, index, rec, heap2); + + ut_a(30 == dfield_get_len(dtuple_get_nth_field(row, 2))); + ut_a(0 == ut_memcmp( + dfield_get_data(dtuple_get_nth_field(row, 2)), + "12345678901234567890123456789", 30)); + + mem_heap_free(heap2); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +} + +/********************************************************************* +Test for massive updates. */ + +ulint +test4mt( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[4000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 4. MULTITHREADED UPDATES\n"); + + thr_no = *((ulint*)arg); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 300; i++) { + + rnd += 874681; + tuple_no = (rnd % 40) * 5 + thr_no; + + dtuple_gen_search_tuple3(entry, tuple_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), buf2, rnd % 3000); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + mem_pool_print_info(mem_comm_pool); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(2000000); + + btr_validate_tree(tree); + + ut_a(trx->conc_state != TRX_ACTIVE); + ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0); + + count++; + + if (count < 2) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for join. */ + +ulint +test6( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ulint count = 0; + dtuple_t* entry; + dict_index_t* index; + dict_tree_t* tree; + btr_pcur_t pcur; + btr_pcur_t pcur2; + mtr_t mtr; + mtr_t mtr2; + ulint rnd; + ulint latch_mode; + + printf("-------------------------------------------------\n"); + printf("TEST 6. MASSIVE EQUIJOIN\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*--------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + /*--------------*/ + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /* Check inserted entries */ + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + table = dict_table_get("TS_TABLE1", trx); + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + oldtm = ut_clock(); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IS, thr)); + + rnd = 98651; + + for (i = 0; i < *((ulint*)arg); i++) { + + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + btr_pcur_store_position(&pcur, &mtr); + + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur), + index)); + + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + if (i % 1211 == 0) { + dummy++; + } + + rnd = 55321; + + dtuple_gen_search_tuple3(entry, rnd % *((ulint*)arg), buf); + +/* if (i == 0) { */ + latch_mode = BTR_SEARCH_LEAF; +/* } else { + latch_mode = BTR_SEARCH_LEAF | BTR_GUESS_LATCH; + } */ + + mtr_start(&mtr2); + + btr_pcur_open(index, entry, PAGE_CUR_LE, latch_mode, + &pcur2, &mtr2); + + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur2), + index)); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur2))); + + mtr_commit(&mtr2); + + mtr_start(&mtr); + + btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + tm = ut_clock(); + printf("Wall time for join of %lu rows %lu milliseconds\n", + i, tm - oldtm); + btr_search_index_print_info(index); + /*-------------------------------------*/ + /* COMMIT */ + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); +/* printf("Wall time for commit %lu milliseconds\n", tm - oldtm); */ + + /*-------------------------------------*/ + count++; +/* btr_validate_tree(tree); */ + + if (count < 3) { + goto loop; + } + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Test for lock wait. Requires Test 4.1 first. */ + +ulint +test7( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + trx_t* trx2; + ulint rnd; + dtuple_t* entry; + dtuple_t* row; + byte buf[100]; + byte buf2[4000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 7. LOCK WAIT\n"); + + thr_no = *((ulint*)arg); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx2 = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + /* UPDATE by trx */ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + ut_a(trx_start(trx2, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 2); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + rnd += 874681; + tuple_no = 3; + + dtuple_gen_search_tuple3(entry, tuple_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), buf2, rnd % 1500); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + tm = ut_clock(); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + + lock_print_info(); + + /*-------------------------------------*/ + /* INSERT by trx2 */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx2; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx2); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx2->sess); + + trx2->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + dtuple_gen_test_tuple3(row, 2, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + /* Insert should be left to wait until trx releases the row lock */ + + que_run_threads(thr); + + tm = ut_clock(); + + lock_validate(); + + lock_print_info(); + + /*-------------------------------------*/ + /* COMMIT of trx */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + + /*-------------------------------------*/ + os_thread_sleep(1000000); + + printf( + "trx2 can now continue to do the insert, after trx committed.\n"); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + + lock_print_info(); + + dict_table_print_by_name("TS_TABLE1"); + + return(0); +} + +/********************************************************************* +Inserts for TPC-A. */ + +ulint +test8A( +/*===*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + btr_pcur_t pcur; + mtr_t mtr; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 8A. 1000 INSERTS FOR TPC-A\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE2", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 1000; i++) { + dtuple_gen_test_tuple_TPC_A(row, rnd, buf); + + rnd = rnd + 1; + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < 1000; i++) { + dtuple_gen_search_tuple_TPC_A(entry, rnd, buf); + + rnd = rnd + 1; + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); + + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + +/* dict_table_print_by_name("TS_TABLE2"); */ + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Test for TPC-A transaction. */ + +ulint +test8( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork1; + que_fork_t* fork2; + que_fork_t* cfork; + dict_table_t* table; + dict_table_t* table2; + que_thr_t* thr; + trx_t* trx; + ulint i; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ins_node_t* inode; + ulint rnd = 0; + + arg = arg; + + printf("-------------------------------------------------\n"); + printf("TEST 8. TPC-A %lu \n", *((ulint*)arg)); + + oldtm = ut_clock(); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + /*-----------------------------------*/ + + fork1 = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork1->trx = trx; + + thr = que_thr_create(fork1, fork1, heap); + + table = dict_table_get("TS_TABLE3", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + inode = ins_node_create(fork1, thr, row, table, heap); + + thr->child = inode; + + row_ins_init_sys_fields_at_sql_compile(inode->row, inode->table, heap); + row_ins_init_sys_fields_at_sql_prepare(inode->row, inode->table, trx); + + inode->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork1, trx->sess); + + trx->graph = fork1; + + mutex_exit(&kernel_mutex); + + fork2 = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork2->trx = trx; + + thr = que_thr_create(fork2, fork2, heap); + + table2 = dict_table_get("TS_TABLE2", trx); + + update = upd_create(1, heap); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 1, table2); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + node = upd_node_create(fork2, thr, table2, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = UPD_NODE_NO_ORD_CHANGE | UPD_NODE_NO_SIZE_CHANGE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork2, trx->sess); + + trx->graph = fork2; + + mutex_exit(&kernel_mutex); + + cfork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + cfork->trx = trx; + + thr = que_thr_create(cfork, cfork, heap); + + thr->child = commit_node_create(cfork, thr, heap); + + oldtm = ut_clock(); + +loop: +/* printf("Round %lu\n", count); */ + + /*-------------------------------------*/ + /* INSERT */ + +/* printf("Trx %lu %lu starts, thr %lu\n", + ut_dulint_get_low(trx->id), + (ulint)trx, + *((ulint*)arg)); */ + + dtuple_gen_test_tuple3(row, count, DTUPLE_TEST_FIXED30, buf); + + ins_node_reset(inode); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork1, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + /*-------------------------------------*/ + /* 3 UPDATES */ + + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IX, thr)); + + for (i = 0; i < 3; i++) { + + rnd += 876751; + + if (count % 1231 == 0) { + dummy++; + } + + dtuple_gen_search_tuple_TPC_A(entry, rnd % 1000, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_LEAF, &pcur, &mtr); + +/* ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); */ + +/* btr_pcur_store_position(&pcur, &mtr); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + ufield = upd_get_nth_field(update, 0); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork2, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + /*-------------------------------------*/ + /* COMMIT */ + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(cfork, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + count++; + + if (count < *((ulint*)arg)) { + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + goto loop; + } + +/* printf("Trx %lu %lu committed\n", ut_dulint_get_low(trx->id), + (ulint)trx); */ + tm = ut_clock(); + printf("Wall time for TPC-A %lu trxs %lu milliseconds\n", + count, tm - oldtm); + + btr_search_index_print_info(index); + btr_search_index_print_info(dict_table_get_first_index(table)); + +/* mem_print_info(); */ + /*-------------------------------------*/ + + +/* dict_table_print_by_name("TS_TABLE2"); + dict_table_print_by_name("TS_TABLE3"); */ + + return(0); +} + +/********************************************************************* +Inserts for TPC-C. */ + +ulint +test9A( +/*===*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; +/* dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; + dict_index_t* index; + dict_tree_t* tree; +*/ + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 9A. INSERTS FOR TPC-C\n"); + +#define TPC_C_TABLE_SIZE 15000 + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE4", trx); + + row = dtuple_create(heap, 12 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < TPC_C_TABLE_SIZE; i++) { + + dtuple_gen_test_tuple_TPC_C(row, rnd, buf); + + rnd = rnd + 1; + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + +#ifdef notdefined + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < TPC_C_TABLE_SIZE; i++) { + + dtuple_gen_search_tuple_TPC_C(entry, rnd, buf); + + rnd = rnd + 1; + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); +#endif + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + +/* dict_table_print_by_name("TS_TABLE4"); */ + +/* mem_heap_free(heap); */ + return(0); +} + +/********************************************************************* +Test for TPC-C transaction. Test 9A must be run first to populate table. */ + +ulint +test9( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork1; + que_fork_t* fork2; + que_fork_t* cfork; + dict_table_t* table; + dict_table_t* table2; + que_thr_t* thr; + trx_t* trx; + ulint j; + ulint i; + byte* ptr; + ulint len; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ins_node_t* inode; + ulint rnd = 0; + byte buf2[240]; + rec_t* rec; + + arg = arg; + + printf("-------------------------------------------------\n"); + printf("TEST 9. TPC-C %lu \n", *((ulint*)arg)); + + oldtm = ut_clock(); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + /*-----------------------------------*/ + + fork1 = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork1->trx = trx; + + thr = que_thr_create(fork1, fork1, heap); + + table = dict_table_get("TS_TABLE3", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + inode = ins_node_create(fork1, thr, row, table, heap); + + thr->child = inode; + + row_ins_init_sys_fields_at_sql_compile(inode->row, inode->table, heap); + row_ins_init_sys_fields_at_sql_prepare(inode->row, inode->table, trx); + + inode->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork1, trx->sess); + + trx->graph = fork1; + + mutex_exit(&kernel_mutex); + + fork2 = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork2->trx = trx; + + thr = que_thr_create(fork2, fork2, heap); + + table2 = dict_table_get("TS_TABLE4", trx); + + update = upd_create(3, heap); + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 1, table2); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table2); + ufield = upd_get_nth_field(update, 2); + + upd_field_set_col_no(ufield, 1, table2); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + node = upd_node_create(fork2, thr, table2, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = UPD_NODE_NO_ORD_CHANGE | UPD_NODE_NO_SIZE_CHANGE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork2, trx->sess); + + trx->graph = fork2; + + mutex_exit(&kernel_mutex); + + cfork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + cfork->trx = trx; + + thr = que_thr_create(cfork, cfork, heap); + + thr->child = commit_node_create(cfork, thr, heap); + + oldtm = ut_clock(); +loop: + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IS, thr)); + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IX, thr)); + +/* printf("Round %lu\n", count); */ + +for (j = 0; j < 13; j++) { + + /*-------------------------------------*/ + /* SELECT FROM 'ITEM' */ + + rnd += 876751; + + dtuple_gen_search_tuple_TPC_C(entry, rnd % TPC_C_TABLE_SIZE, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_S, thr); + ut_a(err == DB_SUCCESS); + + rec = btr_pcur_get_rec(&pcur); + + for (i = 0; i < 5; i++) { + ptr = rec_get_nth_field(rec, i + 2, &len); + + ut_memcpy(buf2 + i * 24, ptr, len); + } + + mtr_commit(&mtr); + + /*-------------------------------------*/ + /* UPDATE 'STOCK' */ + + rnd += 876751; + + if (count % 1231 == 0) { + dummy++; + } + + dtuple_gen_search_tuple_TPC_C(entry, rnd % TPC_C_TABLE_SIZE, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_LEAF, &pcur, &mtr); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + +/* btr_pcur_store_position(&pcur, &mtr); */ + + rec = btr_pcur_get_rec(&pcur); + + for (i = 0; i < 10; i++) { + ptr = rec_get_nth_field(rec, i + 2, &len); + + ut_memcpy(buf2 + i * 24, ptr, len); + } + +/* btr_pcur_commit(&pcur); */ + +/* err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); */ + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur), + index)); +/* ut_a(err == DB_SUCCESS); */ + + ufield = upd_get_nth_field(update, 0); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + ufield = upd_get_nth_field(update, 1); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + ufield = upd_get_nth_field(update, 2); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork2, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + btr_pcur_close(&pcur); + /*-------------------------------------*/ + /* INSERT INTO 'ORDERLINE' */ + +/* printf("Trx %lu %lu starts, thr %lu\n", + ut_dulint_get_low(trx->id), + (ulint)trx, + *((ulint*)arg)); */ + + dtuple_gen_test_tuple3(row, count * 13 + j, DTUPLE_TEST_FIXED30, buf); + + ins_node_reset(inode); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork1, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +} + /*-------------------------------------*/ + /* COMMIT */ + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(cfork, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* printf("Trx %lu %lu committed\n", ut_dulint_get_low(trx->id), + (ulint)trx); */ + count++; + + if (count < *((ulint*)arg)) { + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + goto loop; + } + + tm = ut_clock(); + printf("Wall time for TPC-C %lu trxs %lu milliseconds\n", + count, tm - oldtm); + + btr_search_index_print_info(index); + btr_search_index_print_info(dict_table_get_first_index(table)); + +/* mem_print_info(); */ + /*-------------------------------------*/ +/* dict_table_print_by_name("TS_TABLE2"); + dict_table_print_by_name("TS_TABLE3"); */ + + return(0); +} + +/********************************************************************* +Init for purge test. */ + +ulint +test10_1( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint thr_no; + + thr_no = *((ulint*)arg); + + printf("-------------------------------------------------\n"); + printf("TEST 10.1. PURGE INIT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 200; i++) { + + dtuple_gen_test_tuple3(row, i * 100 + thr_no, + DTUPLE_TEST_FIXED30, buf); + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_2( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[1000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.2. PURGE TEST UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(2, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + tuple_no = i; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + dfield_set_data(&(ufield->new_val), dfield_get_data( + dtuple_get_nth_field(entry, 0)), + dfield_get_len( + dtuple_get_nth_field(entry, 0))); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table); + + rnd += 98326761; + + dfield_set_data(&(ufield->new_val), buf2, rnd % 200); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + fsp_validate(0); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + count++; + + if (count < 1) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_2_r( +/*=======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[1000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.2. PURGE TEST UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(2, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + tuple_no = i; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + dfield_set_data(&(ufield->new_val), dfield_get_data( + dtuple_get_nth_field(entry, 0)), + dfield_get_len( + dtuple_get_nth_field(entry, 0))); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table); + + rnd += 98326761; + + dfield_set_data(&(ufield->new_val), buf2, rnd % 2000); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + fsp_validate(0); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + + mem_pool_print_info(mem_comm_pool); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(2000000); + + count++; + + if (count < 1) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_3( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + btr_pcur_t pcur; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + del_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.3. PURGE TEST DELETES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + node = del_node_create(fork, thr, table, &pcur, heap); + thr->child = node; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + rnd = i; + tuple_no = rnd; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu delete markings %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_5( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + btr_pcur_t pcur; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + del_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.5. PURGE TEST UNCOMMITTED DELETES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + node = del_node_create(fork, thr, table, &pcur, heap); + thr->child = node; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 50; i++) { + + rnd = i; + tuple_no = rnd % 100; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu delete markings %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + return(0); +} + +/********************************************************************* +Multithreaded test for purge. */ + +ulint +test10mt( +/*=====*/ + void* arg) +{ + ulint i; + ulint thr_no; + + thr_no = *((ulint*)arg); + + printf("Thread %lu starts purge test\n", thr_no); + + for (i = 0; i < 2; i++) { + test10_1(arg); + + sync_print(); + + fsp_validate(0); + + test10_2_r(arg); + sync_print(); + + test10_2(arg); + sync_print(); + + lock_validate(); + + test10_3(arg); + sync_print(); + } + + printf("Thread %lu ends purge test\n", thr_no); + + return(0); +} + +/********************************************************************* +Purge test. */ + +ulint +test10_4( +/*=====*/ + void* arg) +{ + ulint i; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 10.4. PURGE TEST\n"); + + for (i = 0; i < 30; i++) { + trx_purge(); + + printf("%lu pages purged\n", purge_sys->n_pages_handled); + + os_thread_sleep(5000000); + } + +/* dict_table_print_by_name("TS_TABLE1"); */ + + return(0); +} + +/********************************************************************* +This thread is used to test insert buffer merge. */ + +ulint +test_ibuf_merge( +/*============*/ + void* arg) +{ + ulint sum_sizes; + ulint volume; + + ut_ad(arg); + + printf("Starting ibuf merge\n"); + + sum_sizes = 0; + volume = 1; + + while (volume) { + volume = ibuf_contract(FALSE); + + sum_sizes += volume; + } + + printf("Ibuf merged %lu bytes\n", sum_sizes); + + os_thread_sleep(5000000); + + return(0); +} + +/********************************************************************* +This thread is used to measure contention of latches. */ + +ulint +test_measure_cont( +/*==============*/ + void* arg) +{ + ulint i, j; + ulint count; + + ut_ad(arg); + + printf("Starting contention measurement\n"); + + for (i = 0; i < 1000; i++) { + count = 0; + + for (j = 0; j < 100; j++) { + + os_thread_sleep(10000); + + if ((&(buf_pool->mutex))->lock_word) { + + count++; + } + } + + printf("Mutex reserved %lu of %lu peeks\n", count, j); + } + + return(0); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + ulint n5000 = 500; + ulint err; + + oldtm = ut_clock(); + +/* buf_debug_prints = TRUE; */ + log_do_write = TRUE; + log_debug_writes = FALSE; +/* btr_search_use_hash = FALSE; */ + + srv_boot("initfile"); + os_aio_init(576, 9, 100); + fil_init(25); + buf_pool_init(POOL_SIZE, POOL_SIZE); + fsp_init(); + log_init(); + lock_sys_create(1024); + + create_files(); + create_log_files(); + + sess_sys_init_at_db_start(); + + mem_validate(); + + /* Tests crash recovery: */ +/* + err = recv_recovery_from_checkpoint_start(LOG_CHECKPOINT, + ut_dulint_max); + ut_a(err == DB_SUCCESS); + + recv_compare_spaces_low(0, 4, 100); + + trx_sys_init_at_db_start(); + + dict_boot(); + + recv_recovery_from_checkpoint_finish(); +*/ + /* Tests archive recovery: */ + + err = recv_recovery_from_archive_start(ut_dulint_max, + "ib_arch_log_0_0000000000"); + ut_a(err == DB_SUCCESS); + + recv_compare_spaces_low(0, 4, 500); + + trx_sys_init_at_db_start(); + + dict_boot(); + + recv_recovery_from_archive_finish(); + +/* test4_2(); */ + + log_make_checkpoint_at(ut_dulint_max); + +/* dict_table_print_by_name("SYS_TABLES"); + + dict_table_print_by_name("SYS_COLUMNS"); + + dict_table_print_by_name("SYS_INDEXES"); */ + + dict_table_print_by_name("TS_TABLE1"); + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/btr/ts/tsrecv97.c b/innobase/btr/ts/tsrecv97.c new file mode 100644 index 00000000000..0f30fcd94f1 --- /dev/null +++ b/innobase/btr/ts/tsrecv97.c @@ -0,0 +1,4909 @@ +/************************************************************************ +Test for the B-tree + +(c) 1994-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "os0proc.h" +#include "sync0sync.h" +#include "ut0mem.h" +#include "mem0mem.h" +#include "mem0pool.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "os0file.h" +#include "os0thread.h" +#include "fil0fil.h" +#include "fsp0fsp.h" +#include "rem0rec.h" +#include "rem0cmp.h" +#include "mtr0mtr.h" +#include "log0log.h" +#include "log0recv.h" +#include "page0page.h" +#include "page0cur.h" +#include "trx0trx.h" +#include "dict0boot.h" +#include "trx0sys.h" +#include "dict0crea.h" +#include "btr0btr.h" +#include "btr0pcur.h" +#include "btr0cur.h" +#include "btr0sea.h" +#include "rem0rec.h" +#include "srv0srv.h" +#include "que0que.h" +#include "com0com.h" +#include "usr0sess.h" +#include "lock0lock.h" +#include "trx0roll.h" +#include "trx0purge.h" +#include "row0ins.h" +#include "row0upd.h" +#include "row0row.h" +#include "row0del.h" +#include "lock0lock.h" +#include "ibuf0ibuf.h" + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[10]; + +mutex_t incs_mutex; +ulint incs; + +byte bigbuf[1000000]; + +#define N_SPACES 3 /* must be >= 2 */ +#define N_FILES 1 +#define FILE_SIZE 512 /* must be > 512 */ +#define POOL_SIZE 1000 +#define IBUF_SIZE 200 +#define COUNTER_OFFSET 1500 + +#define N_LOG_GROUPS 2 +#define N_LOG_FILES 3 +#define LOG_FILE_SIZE 500 + +#define LOOP_SIZE 150 +#define N_THREADS 5 + +#define COUNT 1 + +ulint zero = 0; + +buf_block_t* bl_arr[POOL_SIZE]; + +ulint dummy = 0; + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + ulint i; + + segment = *((ulint*)arg); + + printf("Io handler thread %lu starts\n", segment); + + for (i = 0;; i++) { + fil_aio_wait(segment); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + + } + + return(0); +} + +/************************************************************************* +Creates or opens the log files. */ + +void +create_log_files(void) +/*==================*/ +{ + bool ret; + ulint i, k; + char name[20]; + + printf("--------------------------------------------------------\n"); + printf("Create or open log files\n"); + + strcpy(name, "logfile00"); + + for (k = 0; k < N_LOG_GROUPS; k++) { + for (i = 0; i < N_LOG_FILES; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_AIO, + &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_AIO, &ret); + ut_a(ret); + } else { + ut_a(os_file_set_size(files[i], + 8192 * LOG_FILE_SIZE, 0)); + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k + 100, FIL_LOG); + } + + ut_a(fil_validate()); + + fil_node_create(name, LOG_FILE_SIZE, k + 100); + } + + fil_space_create(name, k + 200, FIL_LOG); + + log_group_init(k, N_LOG_FILES, LOG_FILE_SIZE * UNIV_PAGE_SIZE, + k + 100, k + 200); + } +} + +/************************************************************************* +Creates the files for the file system test and inserts them to the file +system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k; + char name[20]; + os_thread_t thr[10]; + os_thread_id_t id[10]; + + printf("--------------------------------------------------------\n"); + printf("Create or open database files\n"); + + strcpy(name, "tsfile00"); + + for (k = 0; k < 2 * N_SPACES; k += 2) { + for (i = 0; i < N_FILES; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, + OS_FILE_AIO, &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_AIO, &ret); + ut_a(ret); + } else { + if (k == 1) { + ut_a(os_file_set_size(files[i], + 8192 * IBUF_SIZE, 0)); + } else { + ut_a(os_file_set_size(files[i], + 8192 * FILE_SIZE, 0)); + } + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k, FIL_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create(name, FILE_SIZE, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK); + + for (i = 0; i < 9; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/********************************************************************* +Test for table creation. */ + +ulint +test1( +/*==*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1. CREATE TABLE WITH 3 COLUMNS AND WITH 3 INDEXES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE1", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND1", 0, + DICT_UNIQUE | DICT_CLUSTERED, 1); + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND2", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /*-------------------------------------*/ + /* CREATE ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND3", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +#ifdef notdefined + /*-------------------------------------*/ + /* CREATE YET ANOTHER SECONDARY INDEX */ + + index = dict_mem_index_create("TS_TABLE1", "IND4", 0, 0, 1); + + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +#endif +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_5( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.5. CREATE TABLE WITH 3 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE2", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE2", "IND1", 0, + DICT_CLUSTERED | DICT_UNIQUE, 1); + + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_6( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.6. CREATE TABLE WITH 3 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE3", 0, 3); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE3", "IND1", 0, DICT_CLUSTERED, + 2); + dict_mem_index_add_field(index, "COL1", 0); + dict_mem_index_add_field(index, "COL2", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Another test for table creation. */ + +ulint +test1_7( +/*====*/ + void* arg) +{ + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + dict_index_t* index; + dict_table_t* table; + que_fork_t* fork; + que_thr_t* thr; + trx_t* trx; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 1.7. CREATE TABLE WITH 12 COLUMNS AND WITH 1 INDEX\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + table = dict_mem_table_create("TS_TABLE4", 0, 12); + + dict_mem_table_add_col(table, "COL1", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL2", DATA_VARCHAR, + DATA_ENGLISH, 10, 0); + dict_mem_table_add_col(table, "COL3", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL4", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL5", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL6", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL7", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL8", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL9", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL10", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL11", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + dict_mem_table_add_col(table, "COL12", DATA_VARCHAR, + DATA_ENGLISH, 100, 0); + /*------------------------------------*/ + /* CREATE TABLE */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = tab_create_graph_create(fork, thr, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_TABLES"); + dict_table_print_by_name("SYS_COLUMNS"); */ + /*-------------------------------------*/ + /* CREATE CLUSTERED INDEX */ + + index = dict_mem_index_create("TS_TABLE4", "IND1", 0, + DICT_CLUSTERED | DICT_UNIQUE, 1); + + dict_mem_index_add_field(index, "COL1", 0); + + ut_a(mem_heap_validate(index->heap)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = ind_create_graph_create(fork, thr, index, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* dict_table_print_by_name("SYS_INDEXES"); + dict_table_print_by_name("SYS_FIELDS"); */ + + return(0); +} + +/********************************************************************* +Test for inserts. */ + +ulint +test2( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + dict_index_t* index; +/* ulint size; */ + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2. MASSIVE INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + /* MASSIVE RANDOM INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 7857641) % 200000; + + dtuple_gen_test_tuple3(row, rnd, + DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 1000 == 0) { + printf( + "********************************Inserted %lu rows\n", i); + ibuf_print(); + } + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); +/* + for (i = 0; i < 10; i++) { + size = ibuf_contract(TRUE); + + printf("%lu bytes will be contracted\n", size); + + os_thread_sleep(1000000); + } +*/ + index = dict_table_get_next_index(dict_table_get_first_index(table)); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + index = dict_table_get_next_index(index); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + btr_search_print_info(); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 7857641) % 200000; + dtuple_gen_search_tuple3(entry, rnd, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); + +/* btr_print_tree(tree, 5); */ + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + btr_validate_tree(tree); + +/* btr_search_print_info(); + dict_table_print_by_name("TS_TABLE1"); */ + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_1( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ins_node_t* node; + ulint count = 0; + ulint rnd; + dtuple_t* row; +/* dict_tree_t* tree; + dict_index_t* index; + dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; */ + + printf("-------------------------------------------------\n"); + printf("TEST 2.1. MASSIVE ASCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + rnd = 0; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND3500, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 5000 == 0) { + /* ibuf_print(); */ + /* buf_print(); */ + + /* buf_print_io(); */ + + tm = ut_clock(); + /* + printf("Wall time for %lu inserts %lu milliseconds\n", + i, tm - oldtm); */ + } + + rnd = rnd + 1; + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + +#ifdef notdefined +/* dict_table_print_by_name("TS_TABLE1"); */ + + ibuf_print(); + + index = dict_table_get_first_index(table); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + + index = dict_table_get_next_index(index); + + btr_search_index_print_info(index); + + btr_validate_tree(dict_index_get_tree(index)); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + /* Check inserted entries */ + + btr_search_print_info(); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); +#endif +#ifdef notdefined + /*-------------------------------------*/ + /* ROLLBACK */ + +/* btr_validate_tree(tree); */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_search_print_info(); + +#endif + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + /*-------------------------------------*/ + + count++; +/* btr_validate_tree(tree); */ + + if (count < 5) { + goto loop; + } + + mem_heap_free(heap); + + return(0); +} + +/********************************************************************* +Another test for inserts. */ + +ulint +test2_2( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + btr_pcur_t pcur; + mtr_t mtr; + + printf("-------------------------------------------------\n"); + printf("TEST 2.2. MASSIVE DESCENDING INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = *((ulint*)arg) + 1; + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd - 1) % 200000; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + if (i % 1000 == 0) { +/* printf( + "********************************Inserted %lu rows\n", i); + ibuf_print(); */ + } + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /* Check inserted entries */ + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < *((ulint*)arg); i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i + 1, buf); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + btr_validate_tree(tree); +/* dict_table_print_by_name("TS_TABLE1"); */ + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(1000000); + + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + + btr_validate_tree(tree); + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Multithreaded test for random inserts. */ + +ulint +test2mt( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2MT. MULTITHREADED RANDOM INSERT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + rnd = 78675; +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + for (i = 0; i < *((ulint*)arg); i++) { + + if (i % 100 == 0) { +/* buf_print(); */ +/* ibuf_print(); */ + } + + rnd = (rnd + 7857641) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for multithreaded sequential inserts. */ + +ulint +test2_1mt( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2.1MT. MULTITHREADED ASCENDING INSERT\n"); + + rnd = 8757677; + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + rnd += 98667501; + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd + 1) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for multithreaded sequential inserts. */ + +ulint +test2_2mt( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + + printf("-------------------------------------------------\n"); + printf("TEST 2.2MT. MULTITHREADED DESCENDING INSERT\n"); + + rnd = 87677; + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* MASSIVE INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + rnd += 78667; + + for (i = 0; i < *((ulint*)arg); i++) { + + rnd = (rnd - 1) % 500; + + dtuple_gen_test_tuple3(row, rnd, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu inserts %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(3000000); + /*-------------------------------------*/ +#ifdef notdefined + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); +#endif + /*-------------------------------------*/ + count++; + + mem_print_info(); + + if (count < COUNT) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for updates. */ + +ulint +test3( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + byte* ptr; + ulint len; + ulint err; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 3. UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 3; i++) { + dtuple_gen_test_tuple3(row, i, DTUPLE_TEST_RND30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + dict_table_print_by_name("TS_TABLE1"); + /*-------------------------------------*/ + /* UPDATE ROWS */ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + dtuple_gen_test_tuple3(row, 1, DTUPLE_TEST_RND30, buf); + + entry = dtuple_create(heap, 2); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + dfield_copy(dtuple_get_nth_field(entry, 1), + dtuple_get_nth_field(row, 1)); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), "updated field", 14); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + mtr_start(&mtr); + + ut_a(btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr)); + + ptr = rec_get_nth_field(btr_pcur_get_rec(&pcur), 5, &len); + + ut_a(ut_memcmp(ptr, "updated field", 14) == 0); + + btr_pcur_commit(&pcur); + + dict_table_print_by_name("TS_TABLE1"); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + dfield_set_data(&(ufield->new_val), "31415926", 9); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + dict_table_print_by_name("TS_TABLE1"); + /*-------------------------------------*/ + /* ROLLBACK */ +#ifdef notdefined + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ +#endif + dict_table_print_by_name("TS_TABLE1"); + count++; + + if (count < 1) { + goto loop; + } + + return(0); +} + +/********************************************************************* +Init for update test. */ + +ulint +test4_1(void) +/*=========*/ +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + + printf("-------------------------------------------------\n"); + printf("TEST 4.1. UPDATE INIT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 200; i++) { + + dtuple_gen_test_tuple3(row, i, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + dict_table_print_by_name("TS_TABLE1"); + + return(0); +} + +/************************************************************************* +Checks that the multithreaded update test has rolled back its updates. */ + +void +test4_2(void) +/*=========*/ +{ + dtuple_t* entry; + mem_heap_t* heap; + mem_heap_t* heap2; + mtr_t mtr; + byte buf[32]; + sess_t* sess; + com_endpoint_t* com_endpoint; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + dtuple_t* row; + btr_pcur_t pcur; + rec_t* rec; + + printf("-------------------------------------------------\n"); + printf("TEST 4.2. CHECK UPDATE RESULT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*------------------------------------------*/ + + table = dict_table_get("TS_TABLE1", trx); + + index = dict_table_get_first_index(table); + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_a(btr_pcur_is_before_first_in_tree(&pcur, &mtr)); + + for (i = 0; i < 200; i++) { + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + dtuple_gen_search_tuple3(entry, i, buf); + + rec = btr_pcur_get_rec(&pcur); + + ut_a(0 == cmp_dtuple_rec(entry, rec)); + + heap2 = mem_heap_create(200); + + row = row_build(ROW_COPY_DATA, index, rec, heap2); + + ut_a(30 == dfield_get_len(dtuple_get_nth_field(row, 2))); + ut_a(0 == ut_memcmp( + dfield_get_data(dtuple_get_nth_field(row, 2)), + "12345678901234567890123456789", 30)); + + mem_heap_free(heap2); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); +} + +/********************************************************************* +Test for massive updates. */ + +ulint +test4mt( +/*====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[4000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 4. MULTITHREADED UPDATES\n"); + + thr_no = *((ulint*)arg); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 300; i++) { + + rnd += 874681; + tuple_no = (rnd % 40) * 5 + thr_no; + + dtuple_gen_search_tuple3(entry, tuple_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), buf2, rnd % 3000); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + mem_pool_print_info(mem_comm_pool); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(2000000); + + btr_validate_tree(tree); + + ut_a(trx->conc_state != TRX_ACTIVE); + ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0); + + count++; + + if (count < 2) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for join. */ + +ulint +test6( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + byte buf[100]; + ulint count = 0; + dtuple_t* entry; + dict_index_t* index; + dict_tree_t* tree; + btr_pcur_t pcur; + btr_pcur_t pcur2; + mtr_t mtr; + mtr_t mtr2; + ulint rnd; + ulint latch_mode; + + printf("-------------------------------------------------\n"); + printf("TEST 6. MASSIVE EQUIJOIN\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*--------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + /*--------------*/ + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /* Check inserted entries */ + + entry = dtuple_create(heap, 1); + dtuple_gen_search_tuple3(entry, 0, buf); + + mtr_start(&mtr); + + table = dict_table_get("TS_TABLE1", trx); + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + oldtm = ut_clock(); + + btr_pcur_open(index, entry, PAGE_CUR_L, BTR_SEARCH_LEAF, &pcur, &mtr); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IS, thr)); + + rnd = 98651; + + for (i = 0; i < *((ulint*)arg); i++) { + + ut_a(btr_pcur_move_to_next(&pcur, &mtr)); + + btr_pcur_store_position(&pcur, &mtr); + + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur), + index)); + + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + if (i % 1211 == 0) { + dummy++; + } + + rnd = 55321; + + dtuple_gen_search_tuple3(entry, rnd % *((ulint*)arg), buf); + +/* if (i == 0) { */ + latch_mode = BTR_SEARCH_LEAF; +/* } else { + latch_mode = BTR_SEARCH_LEAF | BTR_GUESS_LATCH; + } */ + + mtr_start(&mtr2); + + btr_pcur_open(index, entry, PAGE_CUR_LE, latch_mode, + &pcur2, &mtr2); + + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur2), + index)); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur2))); + + mtr_commit(&mtr2); + + mtr_start(&mtr); + + btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); + } + + ut_a(!btr_pcur_move_to_next(&pcur, &mtr)); + ut_a(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + tm = ut_clock(); + printf("Wall time for join of %lu rows %lu milliseconds\n", + i, tm - oldtm); + btr_search_index_print_info(index); + /*-------------------------------------*/ + /* COMMIT */ + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); +/* printf("Wall time for commit %lu milliseconds\n", tm - oldtm); */ + + /*-------------------------------------*/ + count++; +/* btr_validate_tree(tree); */ + + if (count < 3) { + goto loop; + } + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Test for lock wait. Requires Test 4.1 first. */ + +ulint +test7( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + trx_t* trx2; + ulint rnd; + dtuple_t* entry; + dtuple_t* row; + byte buf[100]; + byte buf2[4000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 7. LOCK WAIT\n"); + + thr_no = *((ulint*)arg); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx2 = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + /* UPDATE by trx */ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + ut_a(trx_start(trx2, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(1, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 2); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + rnd += 874681; + tuple_no = 3; + + dtuple_gen_search_tuple3(entry, tuple_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 2, table); + dfield_set_data(&(ufield->new_val), buf2, rnd % 1500); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + tm = ut_clock(); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + + lock_print_info(); + + /*-------------------------------------*/ + /* INSERT by trx2 */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx2; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx2); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx2->sess); + + trx2->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + dtuple_gen_test_tuple3(row, 2, DTUPLE_TEST_FIXED30, buf); + + mutex_enter(&kernel_mutex); + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + /* Insert should be left to wait until trx releases the row lock */ + + que_run_threads(thr); + + tm = ut_clock(); + + lock_validate(); + + lock_print_info(); + + /*-------------------------------------*/ + /* COMMIT of trx */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + + /*-------------------------------------*/ + os_thread_sleep(1000000); + + printf( + "trx2 can now continue to do the insert, after trx committed.\n"); + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + + lock_validate(); + + lock_print_info(); + + dict_table_print_by_name("TS_TABLE1"); + + return(0); +} + +/********************************************************************* +Inserts for TPC-A. */ + +ulint +test8A( +/*===*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + dict_index_t* index; + dict_tree_t* tree; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + ins_node_t* node; + btr_pcur_t pcur; + mtr_t mtr; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 8A. 1000 INSERTS FOR TPC-A\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE2", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 1000; i++) { + dtuple_gen_test_tuple_TPC_A(row, rnd, buf); + + rnd = rnd + 1; + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < 1000; i++) { + dtuple_gen_search_tuple_TPC_A(entry, rnd, buf); + + rnd = rnd + 1; + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); + + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + +/* dict_table_print_by_name("TS_TABLE2"); */ + + mem_heap_free(heap); + return(0); +} + +/********************************************************************* +Test for TPC-A transaction. */ + +ulint +test8( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork1; + que_fork_t* fork2; + que_fork_t* cfork; + dict_table_t* table; + dict_table_t* table2; + que_thr_t* thr; + trx_t* trx; + ulint i; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ins_node_t* inode; + ulint rnd = 0; + + arg = arg; + + printf("-------------------------------------------------\n"); + printf("TEST 8. TPC-A %lu \n", *((ulint*)arg)); + + oldtm = ut_clock(); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + /*-----------------------------------*/ + + fork1 = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork1->trx = trx; + + thr = que_thr_create(fork1, fork1, heap); + + table = dict_table_get("TS_TABLE3", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + inode = ins_node_create(fork1, thr, row, table, heap); + + thr->child = inode; + + row_ins_init_sys_fields_at_sql_compile(inode->row, inode->table, heap); + row_ins_init_sys_fields_at_sql_prepare(inode->row, inode->table, trx); + + inode->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork1, trx->sess); + + trx->graph = fork1; + + mutex_exit(&kernel_mutex); + + fork2 = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork2->trx = trx; + + thr = que_thr_create(fork2, fork2, heap); + + table2 = dict_table_get("TS_TABLE2", trx); + + update = upd_create(1, heap); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 1, table2); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + node = upd_node_create(fork2, thr, table2, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = UPD_NODE_NO_ORD_CHANGE | UPD_NODE_NO_SIZE_CHANGE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork2, trx->sess); + + trx->graph = fork2; + + mutex_exit(&kernel_mutex); + + cfork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + cfork->trx = trx; + + thr = que_thr_create(cfork, cfork, heap); + + thr->child = commit_node_create(cfork, thr, heap); + + oldtm = ut_clock(); + +loop: +/* printf("Round %lu\n", count); */ + + /*-------------------------------------*/ + /* INSERT */ + +/* printf("Trx %lu %lu starts, thr %lu\n", + ut_dulint_get_low(trx->id), + (ulint)trx, + *((ulint*)arg)); */ + + dtuple_gen_test_tuple3(row, count, DTUPLE_TEST_FIXED30, buf); + + ins_node_reset(inode); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork1, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + /*-------------------------------------*/ + /* 3 UPDATES */ + + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IX, thr)); + + for (i = 0; i < 3; i++) { + + rnd += 876751; + + if (count % 1231 == 0) { + dummy++; + } + + dtuple_gen_search_tuple_TPC_A(entry, rnd % 1000, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_LEAF, &pcur, &mtr); + +/* ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); */ + +/* btr_pcur_store_position(&pcur, &mtr); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + ufield = upd_get_nth_field(update, 0); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork2, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + /*-------------------------------------*/ + /* COMMIT */ + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(cfork, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + count++; + + if (count < *((ulint*)arg)) { + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + goto loop; + } + +/* printf("Trx %lu %lu committed\n", ut_dulint_get_low(trx->id), + (ulint)trx); */ + tm = ut_clock(); + printf("Wall time for TPC-A %lu trxs %lu milliseconds\n", + count, tm - oldtm); + + btr_search_index_print_info(index); + btr_search_index_print_info(dict_table_get_first_index(table)); + +/* mem_print_info(); */ + /*-------------------------------------*/ + + +/* dict_table_print_by_name("TS_TABLE2"); + dict_table_print_by_name("TS_TABLE3"); */ + + return(0); +} + +/********************************************************************* +Inserts for TPC-C. */ + +ulint +test9A( +/*===*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint count = 0; + ins_node_t* node; +/* dtuple_t* entry; + btr_pcur_t pcur; + mtr_t mtr; + dict_index_t* index; + dict_tree_t* tree; +*/ + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 9A. INSERTS FOR TPC-C\n"); + +#define TPC_C_TABLE_SIZE 15000 + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + btr_search_print_info(); + + /*-------------------------------------*/ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE4", trx); + + row = dtuple_create(heap, 12 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + node = ins_node_create(fork, thr, row, table, heap); + + thr->child = node; + + row_ins_init_sys_fields_at_sql_compile(node->row, node->table, heap); + row_ins_init_sys_fields_at_sql_prepare(node->row, node->table, trx); + + node->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < TPC_C_TABLE_SIZE; i++) { + + dtuple_gen_test_tuple_TPC_C(row, rnd, buf); + + rnd = rnd + 1; + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + +#ifdef notdefined + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + btr_validate_tree(tree); + + /* Check inserted entries */ + rnd = 0; + + entry = dtuple_create(heap, 1); + + for (i = 0; i < TPC_C_TABLE_SIZE; i++) { + + dtuple_gen_search_tuple_TPC_C(entry, rnd, buf); + + rnd = rnd + 1; + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, + &mtr); + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + } + + btr_validate_tree(tree); +#endif + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + /*-------------------------------------*/ + count++; + + if (count < 1) { + goto loop; + } + +/* dict_table_print_by_name("TS_TABLE4"); */ + +/* mem_heap_free(heap); */ + return(0); +} + +/********************************************************************* +Test for TPC-C transaction. Test 9A must be run first to populate table. */ + +ulint +test9( +/*==*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork1; + que_fork_t* fork2; + que_fork_t* cfork; + dict_table_t* table; + dict_table_t* table2; + que_thr_t* thr; + trx_t* trx; + ulint j; + ulint i; + byte* ptr; + ulint len; + dtuple_t* row; + dtuple_t* entry; + byte buf[100]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ins_node_t* inode; + ulint rnd = 0; + byte buf2[240]; + rec_t* rec; + + arg = arg; + + printf("-------------------------------------------------\n"); + printf("TEST 9. TPC-C %lu \n", *((ulint*)arg)); + + oldtm = ut_clock(); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + /*-----------------------------------*/ + + fork1 = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork1->trx = trx; + + thr = que_thr_create(fork1, fork1, heap); + + table = dict_table_get("TS_TABLE3", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + inode = ins_node_create(fork1, thr, row, table, heap); + + thr->child = inode; + + row_ins_init_sys_fields_at_sql_compile(inode->row, inode->table, heap); + row_ins_init_sys_fields_at_sql_prepare(inode->row, inode->table, trx); + + inode->init_all_sys_fields = FALSE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork1, trx->sess); + + trx->graph = fork1; + + mutex_exit(&kernel_mutex); + + fork2 = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork2->trx = trx; + + thr = que_thr_create(fork2, fork2, heap); + + table2 = dict_table_get("TS_TABLE4", trx); + + update = upd_create(3, heap); + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 1, table2); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table2); + ufield = upd_get_nth_field(update, 2); + + upd_field_set_col_no(ufield, 1, table2); + + entry = dtuple_create(heap, 1); + dfield_copy(dtuple_get_nth_field(entry, 0), + dtuple_get_nth_field(row, 0)); + + node = upd_node_create(fork2, thr, table2, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = UPD_NODE_NO_ORD_CHANGE | UPD_NODE_NO_SIZE_CHANGE; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork2, trx->sess); + + trx->graph = fork2; + + mutex_exit(&kernel_mutex); + + cfork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + cfork->trx = trx; + + thr = que_thr_create(cfork, cfork, heap); + + thr->child = commit_node_create(cfork, thr, heap); + + oldtm = ut_clock(); +loop: + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IS, thr)); + ut_a(DB_SUCCESS == lock_table(0, table2, LOCK_IX, thr)); + +/* printf("Round %lu\n", count); */ + +for (j = 0; j < 13; j++) { + + /*-------------------------------------*/ + /* SELECT FROM 'ITEM' */ + + rnd += 876751; + + dtuple_gen_search_tuple_TPC_C(entry, rnd % TPC_C_TABLE_SIZE, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_S, thr); + ut_a(err == DB_SUCCESS); + + rec = btr_pcur_get_rec(&pcur); + + for (i = 0; i < 5; i++) { + ptr = rec_get_nth_field(rec, i + 2, &len); + + ut_memcpy(buf2 + i * 24, ptr, len); + } + + mtr_commit(&mtr); + + /*-------------------------------------*/ + /* UPDATE 'STOCK' */ + + rnd += 876751; + + if (count % 1231 == 0) { + dummy++; + } + + dtuple_gen_search_tuple_TPC_C(entry, rnd % TPC_C_TABLE_SIZE, buf); + + index = dict_table_get_first_index(table2); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_LEAF, &pcur, &mtr); + + ut_a(0 == cmp_dtuple_rec(entry, btr_pcur_get_rec(&pcur))); + +/* btr_pcur_store_position(&pcur, &mtr); */ + + rec = btr_pcur_get_rec(&pcur); + + for (i = 0; i < 10; i++) { + ptr = rec_get_nth_field(rec, i + 2, &len); + + ut_memcpy(buf2 + i * 24, ptr, len); + } + +/* btr_pcur_commit(&pcur); */ + +/* err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); */ + ut_a(DB_SUCCESS == lock_clust_rec_cons_read_check( + btr_pcur_get_rec(&pcur), + index)); +/* ut_a(err == DB_SUCCESS); */ + + ufield = upd_get_nth_field(update, 0); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + ufield = upd_get_nth_field(update, 1); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + ufield = upd_get_nth_field(update, 2); + + dfield_set_data(&(ufield->new_val), "1234", 5); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork2, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + btr_pcur_close(&pcur); + /*-------------------------------------*/ + /* INSERT INTO 'ORDERLINE' */ + +/* printf("Trx %lu %lu starts, thr %lu\n", + ut_dulint_get_low(trx->id), + (ulint)trx, + *((ulint*)arg)); */ + + dtuple_gen_test_tuple3(row, count * 13 + j, DTUPLE_TEST_FIXED30, buf); + + ins_node_reset(inode); + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(fork1, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +} + /*-------------------------------------*/ + /* COMMIT */ + + mutex_enter(&kernel_mutex); + + thr = que_fork_start_command(cfork, SESS_COMM_EXECUTE, 0); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + +/* printf("Trx %lu %lu committed\n", ut_dulint_get_low(trx->id), + (ulint)trx); */ + count++; + + if (count < *((ulint*)arg)) { + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + goto loop; + } + + tm = ut_clock(); + printf("Wall time for TPC-C %lu trxs %lu milliseconds\n", + count, tm - oldtm); + + btr_search_index_print_info(index); + btr_search_index_print_info(dict_table_get_first_index(table)); + +/* mem_print_info(); */ + /*-------------------------------------*/ +/* dict_table_print_by_name("TS_TABLE2"); + dict_table_print_by_name("TS_TABLE3"); */ + + return(0); +} + +/********************************************************************* +Init for purge test. */ + +ulint +test10_1( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* row; + byte buf[100]; + ulint thr_no; + + thr_no = *((ulint*)arg); + + printf("-------------------------------------------------\n"); + printf("TEST 10.1. PURGE INIT\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + /*-------------------------------------*/ + /* INSERT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_INSERT, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + row = dtuple_create(heap, 3 + DATA_N_SYS_COLS); + + dict_table_copy_types(row, table); + + thr->child = ins_node_create(fork, thr, row, table, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 0; + + oldtm = ut_clock(); + + for (i = 0; i < 200; i++) { + + dtuple_gen_test_tuple3(row, i * 100 + thr_no, + DTUPLE_TEST_FIXED30, buf); + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + } + + tm = ut_clock(); + printf("Wall time for %lu inserts %lu milliseconds\n", i, tm - oldtm); + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_2( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[1000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.2. PURGE TEST UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(2, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + tuple_no = i; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + dfield_set_data(&(ufield->new_val), dfield_get_data( + dtuple_get_nth_field(entry, 0)), + dfield_get_len( + dtuple_get_nth_field(entry, 0))); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table); + + rnd += 98326761; + + dfield_set_data(&(ufield->new_val), buf2, rnd % 200); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + fsp_validate(0); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + count++; + + if (count < 1) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_2_r( +/*=======*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + byte buf2[1000]; + ulint count = 0; + btr_pcur_t pcur; + upd_t* update; + upd_field_t* ufield; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + upd_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.2. PURGE TEST UPDATES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); +loop: + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + update = upd_create(2, heap); + + node = upd_node_create(fork, thr, table, &pcur, update, heap); + thr->child = node; + + node->cmpl_info = 0; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + rnd = 87607651; + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + tuple_no = i; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + ufield = upd_get_nth_field(update, 0); + + upd_field_set_col_no(ufield, 0, table); + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + dfield_set_data(&(ufield->new_val), dfield_get_data( + dtuple_get_nth_field(entry, 0)), + dfield_get_len( + dtuple_get_nth_field(entry, 0))); + ufield = upd_get_nth_field(update, 1); + + upd_field_set_col_no(ufield, 1, table); + + rnd += 98326761; + + dfield_set_data(&(ufield->new_val), buf2, rnd % 2000); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + fsp_validate(0); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu updates %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + + mem_pool_print_info(mem_comm_pool); + + /*-------------------------------------*/ + /* ROLLBACK */ + + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = roll_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for rollback of %lu updates %lu milliseconds\n", + i, tm - oldtm); + + os_thread_sleep(2000000); + + count++; + + if (count < 1) { + + goto loop; + } + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_3( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + btr_pcur_t pcur; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + del_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.3. PURGE TEST DELETES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + node = del_node_create(fork, thr, table, &pcur, heap); + thr->child = node; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 200; i++) { + + rnd = i; + tuple_no = rnd; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu delete markings %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + /*-------------------------------------*/ + /* COMMIT */ + fork = que_fork_create(NULL, NULL, QUE_FORK_EXECUTE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + thr->child = commit_node_create(fork, thr, heap); + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + ut_a(thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + oldtm = ut_clock(); + + que_run_threads(thr); + + tm = ut_clock(); + printf("Wall time for commit %lu milliseconds\n", tm - oldtm); + + return(0); +} + +/********************************************************************* +Test for purge. */ + +ulint +test10_5( +/*=====*/ + void* arg) +{ + ulint tm, oldtm; + sess_t* sess; + com_endpoint_t* com_endpoint; + mem_heap_t* heap; + que_fork_t* fork; + dict_table_t* table; + que_thr_t* thr; + trx_t* trx; + ulint i; + ulint rnd; + dtuple_t* entry; + byte buf[100]; + btr_pcur_t pcur; + dict_tree_t* tree; + dict_index_t* index; + mtr_t mtr; + del_node_t* node; + ulint err; + ulint thr_no; + ulint tuple_no; + + printf("-------------------------------------------------\n"); + printf("TEST 10.5. PURGE TEST UNCOMMITTED DELETES\n"); + + heap = mem_heap_create(512); + + com_endpoint = (com_endpoint_t*)heap; /* This is a dummy non-NULL + value */ + mutex_enter(&kernel_mutex); + + sess = sess_open(ut_dulint_zero, com_endpoint, (byte*)"user1", 6); + + trx = sess->trx; + + mutex_exit(&kernel_mutex); + + /*-------------------------------------*/ + ut_a(trx_start(trx, ULINT_UNDEFINED)); + + fork = que_fork_create(NULL, NULL, QUE_FORK_UPDATE, heap); + fork->trx = trx; + + thr = que_thr_create(fork, fork, heap); + + table = dict_table_get("TS_TABLE1", trx); + + node = del_node_create(fork, thr, table, &pcur, heap); + thr->child = node; + + mutex_enter(&kernel_mutex); + + que_graph_publish(fork, trx->sess); + + trx->graph = fork; + + mutex_exit(&kernel_mutex); + + entry = dtuple_create(heap, 1); + + oldtm = ut_clock(); + + thr_no = *((ulint*)arg); + + ut_a(DB_SUCCESS == lock_table(0, table, LOCK_IX, thr)); + + for (i = 0; i < 50; i++) { + + rnd = i; + tuple_no = rnd % 100; + + dtuple_gen_search_tuple3(entry, tuple_no * 100 + 10 + thr_no, buf); + + index = dict_table_get_first_index(table); + tree = dict_index_get_tree(index); + + btr_pcur_set_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); + + btr_pcur_store_position(&pcur, &mtr); + +/* printf("Thread %lu to update row %lu\n", thr_no, tuple_no); */ + + err = lock_clust_rec_read_check_and_lock(0, btr_pcur_get_rec(&pcur), + index, LOCK_X, thr); + ut_a(err == DB_SUCCESS); + + btr_pcur_commit(&pcur); + + mutex_enter(&kernel_mutex); + + ut_a( + thr == que_fork_start_command(fork, SESS_COMM_EXECUTE, 0)); + + mutex_exit(&kernel_mutex); + + que_run_threads(thr); + + } /* for (i = ... */ + + tm = ut_clock(); + printf("Wall time for %lu delete markings %lu milliseconds\n", + i, tm - oldtm); + +/* dict_table_print_by_name("TS_TABLE1"); */ + + printf("Validating tree\n"); + btr_validate_tree(tree); + printf("Validated\n"); + +/* lock_print_info(); */ + +/* mem_print_info(); */ + + return(0); +} + +/********************************************************************* +Multithreaded test for purge. */ + +ulint +test10mt( +/*=====*/ + void* arg) +{ + ulint i; + ulint thr_no; + + thr_no = *((ulint*)arg); + + printf("Thread %lu starts purge test\n", thr_no); + + for (i = 0; i < 2; i++) { + test10_1(arg); + + sync_print(); + + fsp_validate(0); + + test10_2_r(arg); + sync_print(); + + test10_2(arg); + sync_print(); + + lock_validate(); + + test10_3(arg); + sync_print(); + } + + printf("Thread %lu ends purge test\n", thr_no); + + return(0); +} + +/********************************************************************* +Purge test. */ + +ulint +test10_4( +/*=====*/ + void* arg) +{ + ulint i; + + UT_NOT_USED(arg); + + printf("-------------------------------------------------\n"); + printf("TEST 10.4. PURGE TEST\n"); + + for (i = 0; i < 30; i++) { + trx_purge(); + + printf("%lu pages purged\n", purge_sys->n_pages_handled); + + os_thread_sleep(5000000); + } + +/* dict_table_print_by_name("TS_TABLE1"); */ + + return(0); +} + +/********************************************************************* +This thread is used to test insert buffer merge. */ + +ulint +test_ibuf_merge( +/*============*/ + void* arg) +{ + ulint sum_sizes; + ulint volume; + + ut_ad(arg); + + printf("Starting ibuf merge\n"); + + sum_sizes = 0; + volume = 1; + + while (volume) { + volume = ibuf_contract(FALSE); + + sum_sizes += volume; + } + + printf("Ibuf merged %lu bytes\n", sum_sizes); + + os_thread_sleep(5000000); + + return(0); +} + +/********************************************************************* +This thread is used to measure contention of latches. */ + +ulint +test_measure_cont( +/*==============*/ + void* arg) +{ + ulint i, j; + ulint count; + + ut_ad(arg); + + printf("Starting contention measurement\n"); + + for (i = 0; i < 1000; i++) { + count = 0; + + for (j = 0; j < 100; j++) { + + os_thread_sleep(10000); + + if ((&(buf_pool->mutex))->lock_word) { + + count++; + } + } + + printf("Mutex reserved %lu of %lu peeks\n", count, j); + } + + return(0); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + ulint n5000 = 500; + ulint err; + + oldtm = ut_clock(); + +/* buf_debug_prints = TRUE; */ + log_do_write = TRUE; + log_debug_writes = FALSE; +/* btr_search_use_hash = FALSE; */ + + srv_boot("initfile"); + os_aio_init(576, 9, 100); + fil_init(25); + buf_pool_init(POOL_SIZE, POOL_SIZE); + fsp_init(); + log_init(); + lock_sys_create(1024); + + create_files(); + create_log_files(); + + sess_sys_init_at_db_start(); + + mem_validate(); + + /* Tests crash recovery: */ +/* + err = recv_recovery_from_checkpoint_start(LOG_CHECKPOINT, + ut_dulint_max); + ut_a(err == DB_SUCCESS); + + recv_compare_spaces_low(0, 4, 100); + + trx_sys_init_at_db_start(); + + dict_boot(); + + recv_recovery_from_checkpoint_finish(); +*/ + /* Tests archive recovery: */ + + err = recv_recovery_from_archive_start(ut_dulint_max, + "ib_arch_log_0_0000000000"); + ut_a(err == DB_SUCCESS); + + recv_compare_spaces_low(0, 4, 500); + + trx_sys_init_at_db_start(); + + dict_boot(); + + recv_recovery_from_archive_finish(); + +/* test4_2(); */ + + log_make_checkpoint_at(ut_dulint_max); + +/* dict_table_print_by_name("SYS_TABLES"); + + dict_table_print_by_name("SYS_COLUMNS"); + + dict_table_print_by_name("SYS_INDEXES"); */ + + dict_table_print_by_name("TS_TABLE1"); + + tm = ut_clock(); + printf("Wall time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/btr/ts/tss.c b/innobase/btr/ts/tss.c new file mode 100644 index 00000000000..4af3fda4415 --- /dev/null +++ b/innobase/btr/ts/tss.c @@ -0,0 +1,397 @@ +/************************************************************************ +Test for the server + +(c) 1996-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "os0proc.h" +#include "sync0sync.h" +#include "ut0mem.h" +#include "mem0mem.h" +#include "mem0pool.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "buf0flu.h" +#include "os0file.h" +#include "os0thread.h" +#include "fil0fil.h" +#include "fsp0fsp.h" +#include "rem0rec.h" +#include "rem0cmp.h" +#include "mtr0mtr.h" +#include "log0log.h" +#include "log0recv.h" +#include "page0page.h" +#include "page0cur.h" +#include "trx0trx.h" +#include "dict0boot.h" +#include "trx0sys.h" +#include "dict0crea.h" +#include "btr0btr.h" +#include "btr0pcur.h" +#include "btr0cur.h" +#include "btr0sea.h" +#include "rem0rec.h" +#include "srv0srv.h" +#include "que0que.h" +#include "com0com.h" +#include "usr0sess.h" +#include "lock0lock.h" +#include "trx0roll.h" +#include "trx0purge.h" +#include "row0ins.h" +#include "row0sel.h" +#include "row0upd.h" +#include "row0row.h" +#include "lock0lock.h" +#include "ibuf0ibuf.h" +#include "pars0pars.h" +#include "btr0sea.h" + +bool measure_cont = FALSE; + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[10]; + +mutex_t incs_mutex; +ulint incs; + +byte rnd_buf[67000]; + + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + ulint i; + + segment = *((ulint*)arg); + + printf("Io handler thread %lu starts\n", segment); + + for (i = 0;; i++) { + fil_aio_wait(segment); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + } + + return(0); +} + +/************************************************************************* +Creates or opens the log files. */ + +void +create_log_files(void) +/*==================*/ +{ + bool ret; + ulint i, k; + char name[20]; + + printf("--------------------------------------------------------\n"); + printf("Create or open log files\n"); + + strcpy(name, "logfile00"); + + for (k = 0; k < srv_n_log_groups; k++) { + + for (i = 0; i < srv_n_log_files; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_AIO, + &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_AIO, &ret); + ut_a(ret); + } else { + ut_a(os_file_set_size(files[i], + 8192 * srv_log_file_size, 0)); + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k + 100, FIL_LOG); + } + + ut_a(fil_validate()); + + fil_node_create(name, srv_log_file_size, k + 100); + } + + fil_space_create(name, k + 200, FIL_LOG); + + log_group_init(k, srv_n_log_files, + srv_log_file_size * UNIV_PAGE_SIZE, + k + 100, k + 200); + } +} + +/************************************************************************* +Creates the files for the file system test and inserts them to the file +system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k; + char name[20]; + os_thread_t thr[10]; + os_thread_id_t id[10]; + + printf("--------------------------------------------------------\n"); + printf("Create or open database files\n"); + + strcpy(name, "tsfile00"); + + for (k = 0; k < 2 * srv_n_spaces; k += 2) { + for (i = 0; i < srv_n_files; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, + OS_FILE_NORMAL, &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_NORMAL, &ret); + ut_a(ret); + } else { + ut_a(os_file_set_size(files[i], + UNIV_PAGE_SIZE * srv_file_size, 0)); + /* Initialize the file contents to a random value */ + /* + for (j = 0; j < srv_file_size; j++) { + + for (c = 0; c < UNIV_PAGE_SIZE; c++) { + + rnd_buf[c] = 0xFF; + } + + os_file_write(files[i], rnd_buf, + UNIV_PAGE_SIZE * j, 0, + UNIV_PAGE_SIZE); + } + */ + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k, FIL_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create(name, srv_file_size, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK); + + /* Create i/o-handler threads: */ + + for (i = 0; i < 9; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/************************************************************************ +Inits space header of space. */ + +void +init_spaces(void) +/*=============*/ +{ + mtr_t mtr; + + mtr_start(&mtr); + + fsp_header_init(0, srv_file_size * srv_n_files, &mtr); + + mtr_commit(&mtr); +} + +/********************************************************************* +This thread is used to measure contention of latches. */ + +ulint +test_measure_cont( +/*==============*/ + void* arg) +{ + ulint i, j, k; + ulint count[8]; + ulint lcount[8]; + ulint lscount; + ulint lkcount; + ulint pcount, kcount, scount; + + UT_NOT_USED(arg); + + printf("Starting contention measurement\n"); + + for (i = 0; i < 1000; i++) { + + for (k = 0; k < 8; k++) { + count[k] = 0; + lcount[k] = 0; + } + + pcount = 0; + kcount = 0; + scount = 0; + lscount = 0; + lkcount = 0; + + for (j = 0; j < 100; j++) { + + if (srv_measure_by_spin) { + ut_delay(ut_rnd_interval(0, 20000)); + } else { + os_thread_sleep(20000); + } + + if (kernel_mutex.lock_word) { + kcount++; + } + + if (lock_kernel_reserved) { + lkcount++; + } + + if (buf_pool->mutex.lock_word) { + pcount++; + } + + if (btr_search_mutex.lock_word) { + scount++; + } + + for (k = 0; k < 8; k++) { + + if (btr_search_sys-> + hash_index->mutexes[k].lock_word) { + + count[k]++; + } + } + + for (k = 0; k < 2; k++) { + + if (lock_sys->rec_hash->mutexes[k].lock_word) { + + lcount[k]++; + } + } + + if (kernel_mutex.lock_word + || lock_sys->rec_hash->mutexes[0].lock_word + || lock_sys->rec_hash->mutexes[1].lock_word) { + + lscount++; + } + } + + printf( +"Mutex res. p %lu, k %lu %lu, %lu %lu %lu s %lu, %lu %lu %lu %lu %lu %lu %lu %lu of %lu\n", + pcount, kcount, lkcount, lcount[0], lcount[1], lscount, scount, + count[0], count[1], count[2], count[3], + count[4], count[5], count[6], count[7], j); + + sync_print_wait_info(); + + printf("N log i/os %lu, n non sea %lu, n sea succ %lu\n", + log_sys->n_log_ios, btr_cur_n_non_sea, + btr_search_n_succ); + } + + return(0); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + os_thread_id_t thread_id; + + log_do_write = TRUE; +/* yydebug = TRUE; */ + + srv_boot("srv_init"); + + os_aio_init(576, 9, 100); + + fil_init(25); + + buf_pool_init(srv_pool_size, srv_pool_size); + + fsp_init(); + log_init(); + + lock_sys_create(srv_lock_table_size); + + create_files(); + create_log_files(); + + init_spaces(); + + sess_sys_init_at_db_start(); + + trx_sys_create(); + + dict_create(); + + log_make_checkpoint_at(ut_dulint_max); + + if (srv_measure_contention) { + os_thread_create(&test_measure_cont, NULL, &thread_id); + } + + if (!srv_log_archive_on) { + + ut_a(DB_SUCCESS == log_archive_noarchivelog()); + } + + srv_master_thread(); + + printf("TESTS COMPLETED SUCCESSFULLY!\n"); + + os_process_exit(0); +} diff --git a/innobase/btr/ts/tssrv.c b/innobase/btr/ts/tssrv.c new file mode 100644 index 00000000000..78d247968d5 --- /dev/null +++ b/innobase/btr/ts/tssrv.c @@ -0,0 +1,535 @@ +/************************************************************************ +Test for the server + +(c) 1996-1997 Innobase Oy + +Created 2/16/1996 Heikki Tuuri +*************************************************************************/ + +#include "os0proc.h" +#include "sync0sync.h" +#include "ut0mem.h" +#include "mem0mem.h" +#include "mem0pool.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "buf0flu.h" +#include "os0file.h" +#include "os0thread.h" +#include "fil0fil.h" +#include "fsp0fsp.h" +#include "rem0rec.h" +#include "rem0cmp.h" +#include "mtr0mtr.h" +#include "log0log.h" +#include "log0recv.h" +#include "page0page.h" +#include "page0cur.h" +#include "trx0trx.h" +#include "dict0boot.h" +#include "trx0sys.h" +#include "dict0crea.h" +#include "btr0btr.h" +#include "btr0pcur.h" +#include "btr0cur.h" +#include "btr0sea.h" +#include "rem0rec.h" +#include "srv0srv.h" +#include "que0que.h" +#include "com0com.h" +#include "usr0sess.h" +#include "lock0lock.h" +#include "trx0roll.h" +#include "trx0purge.h" +#include "row0ins.h" +#include "row0sel.h" +#include "row0upd.h" +#include "row0row.h" +#include "lock0lock.h" +#include "ibuf0ibuf.h" +#include "pars0pars.h" +#include "btr0sea.h" + +bool measure_cont = FALSE; + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[10]; + +mutex_t incs_mutex; +ulint incs; + +byte rnd_buf[67000]; + +ulint glob_var1 = 0; +ulint glob_var2 = 0; + +mutex_t mutex2; + +mutex_t test_mutex1; +mutex_t test_mutex2; + +mutex_t* volatile mutexes; + +bool always_false = FALSE; + +ulint* test_array; + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + ulint i; + + segment = *((ulint*)arg); + + printf("Io handler thread %lu starts\n", segment); + + for (i = 0;; i++) { + fil_aio_wait(segment); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + } + + return(0); +} + +/************************************************************************* +Creates or opens the log files. */ + +void +create_log_files(void) +/*==================*/ +{ + bool ret; + ulint i, k; + char name[20]; + + printf("--------------------------------------------------------\n"); + printf("Create or open log files\n"); + + strcpy(name, "logfile00"); + + for (k = 0; k < srv_n_log_groups; k++) { + + for (i = 0; i < srv_n_log_files; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_AIO, + &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_AIO, &ret); + ut_a(ret); + } else { + ut_a(os_file_set_size(files[i], + 8192 * srv_log_file_size, 0)); + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k + 100, FIL_LOG); + } + + ut_a(fil_validate()); + + fil_node_create(name, srv_log_file_size, k + 100); + } + + fil_space_create(name, k + 200, FIL_LOG); + + log_group_init(k, srv_n_log_files, + srv_log_file_size * UNIV_PAGE_SIZE, + k + 100, k + 200); + } +} + +/************************************************************************* +Creates the files for the file system test and inserts them to the file +system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k; + char name[20]; + os_thread_t thr[10]; + os_thread_id_t id[10]; + + printf("--------------------------------------------------------\n"); + printf("Create or open database files\n"); + + strcpy(name, "tsfile00"); + + for (k = 0; k < 2 * srv_n_spaces; k += 2) { + for (i = 0; i < srv_n_files; i++) { + + name[6] = (char)((ulint)'0' + k); + name[7] = (char)((ulint)'0' + i); + + files[i] = os_file_create(name, OS_FILE_CREATE, + OS_FILE_NORMAL, &ret); + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_NORMAL, &ret); + ut_a(ret); + } else { + ut_a(os_file_set_size(files[i], + UNIV_PAGE_SIZE * srv_file_size, 0)); + /* Initialize the file contents to a random value */ + /* + for (j = 0; j < srv_file_size; j++) { + + for (c = 0; c < UNIV_PAGE_SIZE; c++) { + + rnd_buf[c] = 0xFF; + } + + os_file_write(files[i], rnd_buf, + UNIV_PAGE_SIZE * j, 0, + UNIV_PAGE_SIZE); + } + */ + } + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create(name, k, FIL_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create(name, srv_file_size, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK); + + /* Create i/o-handler threads: */ + + for (i = 0; i < 9; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/************************************************************************ +Inits space header of space. */ + +void +init_spaces(void) +/*=============*/ +{ + mtr_t mtr; + + mtr_start(&mtr); + + fsp_header_init(0, srv_file_size * srv_n_files, &mtr); + + mtr_commit(&mtr); +} + +/********************************************************************* +This thread is used to measure contention of latches. */ + +ulint +test_measure_cont( +/*==============*/ + void* arg) +{ + ulint i, j; + ulint pcount, kcount, s_scount, s_xcount, s_mcount, lcount; + ulint t1count; + ulint t2count; + + UT_NOT_USED(arg); + + printf("Starting contention measurement\n"); + + for (i = 0; i < 1000; i++) { + + pcount = 0; + kcount = 0; + s_scount = 0; + s_xcount = 0; + s_mcount = 0; + lcount = 0; + t1count = 0; + t2count = 0; + + for (j = 0; j < 100; j++) { + + if (srv_measure_by_spin) { + ut_delay(ut_rnd_interval(0, 20000)); + } else { + os_thread_sleep(20000); + } + + if (kernel_mutex.lock_word) { + kcount++; + } + + if (buf_pool->mutex.lock_word) { + pcount++; + } + + if (log_sys->mutex.lock_word) { + lcount++; + } + + if (btr_search_latch.reader_count) { + s_scount++; + } + + if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED) { + s_xcount++; + } + + if (btr_search_latch.mutex.lock_word) { + s_mcount++; + } + + if (test_mutex1.lock_word) { + t1count++; + } + + if (test_mutex2.lock_word) { + t2count++; + } + } + + printf( + "Mutex res. l %lu, p %lu, k %lu s x %lu s s %lu s mut %lu of %lu\n", + lcount, pcount, kcount, s_xcount, s_scount, s_mcount, j); + + sync_print_wait_info(); + + printf( + "log i/o %lu n non sea %lu n succ %lu n h fail %lu\n", + log_sys->n_log_ios, btr_cur_n_non_sea, + btr_search_n_succ, btr_search_n_hash_fail); + } + + return(0); +} + +/********************************************************************* +This thread is used to test contention of latches. */ + +ulint +test_sync( +/*======*/ + void* arg) +{ + ulint tm, oldtm; + ulint i, j; + ulint sum; + ulint rnd = ut_rnd_gen_ulint(); + ulint mut_ind; + byte* ptr; + + UT_NOT_USED(arg); + + printf("Starting mutex reservation test\n"); + + oldtm = ut_clock(); + + sum = 0; + rnd = 87354941; + + for (i = 0; i < srv_test_n_loops; i++) { + + for (j = 0; j < srv_test_n_free_rnds; j++) { + rnd += 423087123; + + sum += test_array[rnd % (256 * srv_test_array_size)]; + } + + rnd += 43605677; + + mut_ind = rnd % srv_test_n_mutexes; + + mutex_enter(mutexes + mut_ind); + + for (j = 0; j < srv_test_n_reserved_rnds; j++) { + rnd += 423087121; + + sum += test_array[rnd % (256 * srv_test_array_size)]; + } + + mutex_exit(mutexes + mut_ind); + + if (srv_test_cache_evict) { + ptr = (byte*)(mutexes + mut_ind); + + for (j = 0; j < 4; j++) { + ptr += 256 * 1024; + sum += *((ulint*)ptr); + } + } + } + + if (always_false) { + printf("%lu", sum); + } + + tm = ut_clock(); + + printf("Wall time for res. test %lu milliseconds\n", tm - oldtm); + + return(0); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + os_thread_id_t thread_ids[1000]; + ulint tm, oldtm; + ulint rnd; + ulint i, sum; + byte* ptr; +/* mutex_t mutex; */ + + log_do_write = TRUE; +/* yydebug = TRUE; */ + + srv_boot("srv_init"); + + os_aio_init(576, 9, 100); + + fil_init(25); + + buf_pool_init(srv_pool_size, srv_pool_size); + + fsp_init(); + log_init(); + + lock_sys_create(srv_lock_table_size); + + create_files(); + create_log_files(); + + init_spaces(); + + sess_sys_init_at_db_start(); + + trx_sys_create(); + + dict_create(); + + log_make_checkpoint_at(ut_dulint_max); + + printf("Hotspot semaphore addresses k %lx, p %lx, l %lx, s %lx\n", + &kernel_mutex, &(buf_pool->mutex), + &(log_sys->mutex), &btr_search_latch); + + if (srv_measure_contention) { + os_thread_create(&test_measure_cont, NULL, thread_ids + 999); + } + + if (!srv_log_archive_on) { + + ut_a(DB_SUCCESS == log_archive_noarchivelog()); + } + +/* + mutex_create(&mutex); + + oldtm = ut_clock(); + + for (i = 0; i < 2000000; i++) { + + mutex_enter(&mutex); + + mutex_exit(&mutex); + } + + tm = ut_clock(); + + printf("Wall clock time for %lu mutex enter %lu milliseconds\n", + i, tm - oldtm); +*/ + if (srv_test_sync) { + if (srv_test_nocache) { + mutexes = os_mem_alloc_nocache(srv_test_n_mutexes + * sizeof(mutex_t)); + } else { + mutexes = mem_alloc(srv_test_n_mutexes + * sizeof(mutex_t)); + } + + sum = 0; + + rnd = 492314896; + + oldtm = ut_clock(); + + for (i = 0; i < 4000000; i++) { + + rnd += 85967944; + + ptr = ((byte*)(mutexes)) + (rnd % (srv_test_n_mutexes + * sizeof(mutex_t))); + sum += *((ulint*)ptr); + } + + tm = ut_clock(); + + printf( + "Wall clock time for %lu random access %lu milliseconds\n", + i, tm - oldtm); + if (always_false) { + printf("%lu", sum); + } + + test_array = mem_alloc(4 * 256 * srv_test_array_size); + + for (i = 0; i < srv_test_n_mutexes; i++) { + + mutex_create(mutexes + i); + } + + for (i = 0; i < srv_test_n_threads; i++) { + os_thread_create(&test_sync, NULL, thread_ids + i); + } + } + + srv_master_thread(NULL); + + printf("TESTS COMPLETED SUCCESSFULLY!\n"); + + os_process_exit(0); +} |