Commit 38bd84b7 authored by serg@serg.mysql.com's avatar serg@serg.mysql.com

Merge work:/home/bk/mysql-4.0

into serg.mysql.com:/usr/home/serg/Abk/mysql-4.0
parents 65e05c5d da96aaed
...@@ -255,6 +255,7 @@ libmysqld/opt_sum.cc ...@@ -255,6 +255,7 @@ libmysqld/opt_sum.cc
libmysqld/password.c libmysqld/password.c
libmysqld/procedure.cc libmysqld/procedure.cc
libmysqld/records.cc libmysqld/records.cc
libmysqld/repl_failsafe.cc
libmysqld/simple-test libmysqld/simple-test
libmysqld/slave.cc libmysqld/slave.cc
libmysqld/sql_acl.cc libmysqld/sql_acl.cc
......
...@@ -153,7 +153,7 @@ if ($opt_stage <= 1) ...@@ -153,7 +153,7 @@ if ($opt_stage <= 1)
{ {
$opt_config_options.= " --with-innodb" $opt_config_options.= " --with-innodb"
} }
check_system("$opt_config_env ./configure --prefix=/usr/local/mysql \"--with-comment=Official MySQL$version_suffix binary\" --with-extra-charsets=complex \"--with-server-suffix=$version_suffix\" $opt_config_options","Thank you for choosing MySQL"); check_system("$opt_config_env ./configure --prefix=/usr/local/mysql \"--with-comment=Official MySQL$version_suffix binary\" --with-extra-charsets=complex \"--with-server-suffix=$version_suffix\" --enable-thread-safe-client $opt_config_options","Thank you for choosing MySQL");
if (-d "$pwd/$host/include-mysql") if (-d "$pwd/$host/include-mysql")
{ {
safe_system("cp -r $pwd/$host/include-mysql/* $pwd/$host/$ver/include"); safe_system("cp -r $pwd/$host/include-mysql/* $pwd/$host/$ver/include");
...@@ -215,7 +215,7 @@ if ($opt_stage <= 5 && !$opt_no_test && !$opt_no_mysqltest) ...@@ -215,7 +215,7 @@ if ($opt_stage <= 5 && !$opt_no_test && !$opt_no_mysqltest)
{ {
system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir); system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir);
safe_cd("${test_dir}/mysql-test"); safe_cd("${test_dir}/mysql-test");
check_system("./mysql-test-run --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --sleep=10", "tests were successful"); check_system("./mysql-test-run --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful");
} }
# Start the server if we are going to run any of the benchmarks # Start the server if we are going to run any of the benchmarks
...@@ -317,7 +317,7 @@ exit 0; ...@@ -317,7 +317,7 @@ exit 0;
sub usage sub usage
{ {
print <<EOF; print <<EOF;
$0 version 1.3 $0 version 1.4
$0 takes the following options: $0 takes the following options:
...@@ -549,7 +549,8 @@ sub kill_all ...@@ -549,7 +549,8 @@ sub kill_all
chop($cand); chop($cand);
($pid_user, $pid) = split(' ', $cand); ($pid_user, $pid) = split(' ', $cand);
next if $pid == $$; next if $pid == $$;
next process if (! ($cand =~ $pattern) || $pid_user ne $user) next process if (! ($cand =~ $pattern) || $pid_user ne $user);
print LOG "Killing $_\n";
&killpid($pid); &killpid($pid);
} }
} }
......
...@@ -481,6 +481,27 @@ Functions i mysys: (For flags se my_sys.h) ...@@ -481,6 +481,27 @@ Functions i mysys: (For flags se my_sys.h)
void end_key_cache _A((void)); void end_key_cache _A((void));
- End key-cacheing. - End key-cacheing.
@node DBUG,,,
@chapter The DBUG tags to use:
Here is some of the tags we now use:
(We should probably add a couple of new ones)
"enter" Arguments to the function.
"exit" Results from the function.
"info" is something that may be interesting.
"warning" is when something doesn't go the usual route or may be wrong.
"error" when something went wrong.
"loop" write in a loop, that is probably only useful when debugging
the loop. These should normally be deleted when on is
satisfied with the code and it has been in real use for a while.
Some specific to mysqld, because we want to watch these carefully:
"trans" Starting/stopping transactions.
"quit" 'info' when mysqld is preparing to die.
"query" Print query
@node protocol,,, @node protocol,,,
@chapter MySQL client/server protocol @chapter MySQL client/server protocol
......
...@@ -2433,7 +2433,7 @@ mysql> SHOW STATUS; ...@@ -2433,7 +2433,7 @@ mysql> SHOW STATUS;
If a bug or problem occurs while running @strong{mysqld}, try to provide an If a bug or problem occurs while running @strong{mysqld}, try to provide an
input script that will reproduce the anomaly. This script should include any input script that will reproduce the anomaly. This script should include any
necessary source files. The more closely the script can reproduce your necessary source files. The more closely the script can reproduce your
situation, the better. If you can make a repeatable test case, you should situation, the better. If you can make a reproduceable test case, you should
post this to @email{bugs@@lists.mysql.com} for a high priority treatment! post this to @email{bugs@@lists.mysql.com} for a high priority treatment!
If you can't provide a script, you should at least include the output If you can't provide a script, you should at least include the output
...@@ -3532,12 +3532,18 @@ an application when you delete records from a table that has a foreign key. ...@@ -3532,12 +3532,18 @@ an application when you delete records from a table that has a foreign key.
In practice this is as quick (in some cases quicker) and much more portable In practice this is as quick (in some cases quicker) and much more portable
than using foreign keys. than using foreign keys.
In MySQL 4.0 you can use multi-table delete to delete rows from many
tables with one command. @xref{DELETE}.
In the near future we will extend the @code{FOREIGN KEY} implementation so In the near future we will extend the @code{FOREIGN KEY} implementation so
that at least the information will be saved in the table specification file that at least the information will be saved in the table specification file
and may be retrieved by @code{mysqldump} and ODBC. At a later stage we will and may be retrieved by @code{mysqldump} and ODBC. At a later stage we will
implement the foreign key constraints for application that can't easily be implement the foreign key constraints for application that can't easily be
coded to avoid them. coded to avoid them.
MySQL 3.23.44 and forwards, InnoDB tables supports checking of foreign
key constraints. @xref{InnoDB}.
@menu @menu
* Broken Foreign KEY:: Reasons NOT to use foreign keys constraints * Broken Foreign KEY:: Reasons NOT to use foreign keys constraints
@end menu @end menu
...@@ -4033,8 +4039,13 @@ If the date is totally wrong, MySQL will store the special ...@@ -4033,8 +4039,13 @@ If the date is totally wrong, MySQL will store the special
0000-00-00 date value in the column. 0000-00-00 date value in the column.
@item @item
If you set an @code{enum} to an unsupported value, it will be set to If you set an @code{ENUM} column to an unsupported value, it will be set to
the error value 'empty string', with numeric value 0. the error value 'empty string', with numeric value 0.
@item
If you set an @code{SET} column to an unsupported value, the value will
be ignored. @xref{Bugs}.
@end itemize @end itemize
@item @item
...@@ -4775,7 +4786,7 @@ Included in the MySQL distribution are two different testing suites, ...@@ -4775,7 +4786,7 @@ Included in the MySQL distribution are two different testing suites,
@file{mysql-test-run} and @file{mysql-test-run} and
@uref{http://www.mysql.com/information/crash-me.php,crash-me}, as well @uref{http://www.mysql.com/information/crash-me.php,crash-me}, as well
as a benchmark suite. The test system is actively updated with code to as a benchmark suite. The test system is actively updated with code to
test each new feature and almost all repeatable bugs that have come to test each new feature and almost all reproduceable bugs that have come to
our attention. We test MySQL with these on a lot of platforms before our attention. We test MySQL with these on a lot of platforms before
every release. These tests are more sophisticated than anything we have every release. These tests are more sophisticated than anything we have
seen from PostgreSQL, and they ensures that the MySQL is kept to a high seen from PostgreSQL, and they ensures that the MySQL is kept to a high
...@@ -4934,6 +4945,18 @@ Standard usage in PostgreSQL is closer to ANSI SQL in some cases. ...@@ -4934,6 +4945,18 @@ Standard usage in PostgreSQL is closer to ANSI SQL in some cases.
@item @item
One can speed up PostgreSQL by coding things as stored procedures. One can speed up PostgreSQL by coding things as stored procedures.
@item
For geographical data, R-TREES makes PostgreSQL better than MySQL.
@item
The PostgreSQL optimizer can do some optimization that the current MySQL
optimizer can't do. Most notable is doing joins when you don't have the
proper keys in place and doing a join where you are using different keys
combined with OR. The MySQL benchmark suite at
@uref{http://www.mysql.com/information/benchmarks.html} shows you what
kind of constructs you should watch out for when using different
databases.
@item @item
PostgreSQL has a bigger team of developers that contribute to the server. PostgreSQL has a bigger team of developers that contribute to the server.
@end itemize @end itemize
...@@ -29146,6 +29169,9 @@ specified at table creation time. For example, if a column is specified as ...@@ -29146,6 +29169,9 @@ specified at table creation time. For example, if a column is specified as
@code{SET("a","b","c","d")}, then @code{"a,d"}, @code{"d,a"}, and @code{SET("a","b","c","d")}, then @code{"a,d"}, @code{"d,a"}, and
@code{"d,a,a,d,d"} will all appear as @code{"a,d"} when retrieved. @code{"d,a,a,d,d"} will all appear as @code{"a,d"} when retrieved.
If you set a @code{SET} column to an unsupported value, the value will
be ignored.
@code{SET} values are sorted numerically. @code{NULL} values sort before @code{SET} values are sorted numerically. @code{NULL} values sort before
non-@code{NULL} @code{SET} values. non-@code{NULL} @code{SET} values.
...@@ -33790,8 +33816,10 @@ column in a table, the default value is the current date and time. ...@@ -33790,8 +33816,10 @@ column in a table, the default value is the current date and time.
@xref{Date and time types}. @xref{Date and time types}.
@item @item
For string types other than @code{ENUM}, the default value is the empty string. For string types other than @code{ENUM}, the default value is the empty
For @code{ENUM}, the default is the first enumeration value. string. For @code{ENUM}, the default is the first enumeration value (if
you haven't explicitely specified another default value with the
@code{DEFAULT} directive).
@end itemize @end itemize
Default values must be constants. This means, for example, that you cannot Default values must be constants. This means, for example, that you cannot
...@@ -1150,9 +1150,9 @@ static void dumpTable(uint numFields, char *table) ...@@ -1150,9 +1150,9 @@ static void dumpTable(uint numFields, char *table)
} }
if (opt_lock) if (opt_lock)
fputs("UNLOCK TABLES;\n", md_result_file); fputs("UNLOCK TABLES;\n", md_result_file);
mysql_free_result(res);
if (opt_autocommit) if (opt_autocommit)
fprintf(md_result_file, "commit;\n"); fprintf(md_result_file, "commit;\n");
mysql_free_result(res);
} }
} /* dumpTable */ } /* dumpTable */
......
...@@ -17,27 +17,15 @@ ...@@ -17,27 +17,15 @@
#define MANAGER_CLIENT_VERSION "1.0" #define MANAGER_CLIENT_VERSION "1.0"
#include <my_global.h> #include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <mysql.h> #include <mysql.h>
#include <mysql_version.h> #include <mysql_version.h>
#include <m_ctype.h>
#ifdef OS2
#include <config-os2.h>
#else
#include <my_config.h>
#endif
#include <my_dir.h>
#include <hash.h>
#include <mysqld_error.h> #include <mysqld_error.h>
#include <stdio.h> #include <my_sys.h>
#include <stdlib.h> #include <m_string.h>
#include <getopt.h> #include <getopt.h>
#include <stdarg.h> #include <stdarg.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include <violite.h>
#ifndef MYSQL_MANAGER_PORT #ifndef MYSQL_MANAGER_PORT
#define MYSQL_MANAGER_PORT 23546 #define MYSQL_MANAGER_PORT 23546
......
...@@ -92,7 +92,7 @@ static char *db = 0, *pass=0; ...@@ -92,7 +92,7 @@ static char *db = 0, *pass=0;
const char* user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; const char* user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./";
static int port = 0, opt_big_test=0, opt_compress=0; static int port = 0, opt_big_test=0, opt_compress=0;
static uint start_lineno, *lineno; static uint start_lineno, *lineno;
const char* manager_user="root",*manager_host="localhost"; const char* manager_user="root",*manager_host=0;
char *manager_pass=0; char *manager_pass=0;
int manager_port=MYSQL_MANAGER_PORT; int manager_port=MYSQL_MANAGER_PORT;
int manager_wait_timeout=3; int manager_wait_timeout=3;
...@@ -181,7 +181,7 @@ Q_PING, Q_EVAL, ...@@ -181,7 +181,7 @@ Q_PING, Q_EVAL,
Q_RPL_PROBE, Q_ENABLE_RPL_PARSE, Q_RPL_PROBE, Q_ENABLE_RPL_PARSE,
Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT, Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
Q_SERVER_START, Q_SERVER_STOP, Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER,
Q_UNKNOWN, /* Unknown command. */ Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */ Q_COMMENT, /* Comments, ignored. */
Q_COMMENT_WITH_COMMAND Q_COMMENT_WITH_COMMAND
...@@ -215,6 +215,7 @@ const char *command_names[] = { ...@@ -215,6 +215,7 @@ const char *command_names[] = {
"disable_rpl_parse", "eval_result", "disable_rpl_parse", "eval_result",
"enable_query_log", "disable_query_log", "enable_query_log", "disable_query_log",
"server_start", "server_stop", "server_start", "server_stop",
"require_manager",
0 0
}; };
...@@ -640,6 +641,13 @@ int open_file(const char* name) ...@@ -640,6 +641,13 @@ int open_file(const char* name)
return 0; return 0;
} }
int do_require_manager(struct st_query* __attribute__((unused)) q)
{
if (!manager)
abort_not_supported_test();
return 0;
}
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
int do_server_start(struct st_query* q) int do_server_start(struct st_query* q)
{ {
...@@ -655,6 +663,10 @@ int do_server_op(struct st_query* q,const char* op) ...@@ -655,6 +663,10 @@ int do_server_op(struct st_query* q,const char* op)
{ {
char* p=q->first_argument; char* p=q->first_argument;
char com_buf[256],*com_p; char com_buf[256],*com_p;
if (!manager)
{
die("Manager is not initialized, manager commands are not possible");
}
com_p=strmov(com_buf,op); com_p=strmov(com_buf,op);
com_p=strmov(com_p,"_exec "); com_p=strmov(com_p,"_exec ");
if (!*p) if (!*p)
...@@ -1926,7 +1938,9 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) ...@@ -1926,7 +1938,9 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
ds= &ds_res; ds= &ds_res;
if ((flags & QUERY_SEND) && mysql_send_query(mysql, query, query_len)) if ((flags & QUERY_SEND) && mysql_send_query(mysql, query, query_len))
die("At line %u: unable to send query '%s'", start_lineno, query); die("At line %u: unable to send query '%s'(mysql_errno=%d,errno=%d)",
start_lineno, query,
mysql_errno(mysql), errno);
if ((flags & QUERY_SEND) && !disable_query_log) if ((flags & QUERY_SEND) && !disable_query_log)
{ {
dynstr_append_mem(ds,query,query_len); dynstr_append_mem(ds,query,query_len);
...@@ -2196,6 +2210,7 @@ int main(int argc, char** argv) ...@@ -2196,6 +2210,7 @@ int main(int argc, char** argv)
*++cur_file = stdin; *++cur_file = stdin;
*lineno=1; *lineno=1;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if (manager_host)
init_manager(); init_manager();
#endif #endif
if (!( mysql_init(&cur_con->mysql))) if (!( mysql_init(&cur_con->mysql)))
...@@ -2231,6 +2246,7 @@ int main(int argc, char** argv) ...@@ -2231,6 +2246,7 @@ int main(int argc, char** argv)
case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; case Q_DISABLE_QUERY_LOG: disable_query_log=1; break;
case Q_SOURCE: do_source(q); break; case Q_SOURCE: do_source(q); break;
case Q_SLEEP: do_sleep(q); break; case Q_SLEEP: do_sleep(q); break;
case Q_REQUIRE_MANAGER: do_require_manager(q); break;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
case Q_SERVER_START: do_server_start(q); break; case Q_SERVER_START: do_server_start(q); break;
case Q_SERVER_STOP: do_server_stop(q); break; case Q_SERVER_STOP: do_server_stop(q); break;
......
...@@ -2347,6 +2347,8 @@ btr_validate_level( ...@@ -2347,6 +2347,8 @@ btr_validate_level(
mtr_start(&mtr); mtr_start(&mtr);
mtr_x_lock(dict_tree_get_lock(tree), &mtr);
page = btr_root_get(tree, &mtr); page = btr_root_get(tree, &mtr);
space = buf_frame_get_space_id(page); space = buf_frame_get_space_id(page);
......
...@@ -256,7 +256,8 @@ btr_cur_search_to_nth_level( ...@@ -256,7 +256,8 @@ btr_cur_search_to_nth_level(
#ifdef UNIV_SEARCH_PERF_STAT #ifdef UNIV_SEARCH_PERF_STAT
info->n_searches++; info->n_searches++;
#endif #endif
if (latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED
&& latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
&& !estimate && !estimate
&& btr_search_guess_on_hash(index, info, tuple, mode, && btr_search_guess_on_hash(index, info, tuple, mode,
latch_mode, cursor, latch_mode, cursor,
...@@ -344,9 +345,7 @@ btr_cur_search_to_nth_level( ...@@ -344,9 +345,7 @@ btr_cur_search_to_nth_level(
retry_page_get: retry_page_get:
page = buf_page_get_gen(space, page_no, rw_latch, guess, page = buf_page_get_gen(space, page_no, rw_latch, guess,
buf_mode, buf_mode,
#ifdef UNIV_SYNC_DEBUG
IB__FILE__, __LINE__, IB__FILE__, __LINE__,
#endif
mtr); mtr);
if (page == NULL) { if (page == NULL) {
...@@ -515,9 +514,7 @@ btr_cur_open_at_index_side( ...@@ -515,9 +514,7 @@ btr_cur_open_at_index_side(
for (;;) { for (;;) {
page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL, page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
BUF_GET, BUF_GET,
#ifdef UNIV_SYNC_DEBUG
IB__FILE__, __LINE__, IB__FILE__, __LINE__,
#endif
mtr); mtr);
ut_ad(0 == ut_dulint_cmp(tree->id, ut_ad(0 == ut_dulint_cmp(tree->id,
btr_page_get_index_id(page))); btr_page_get_index_id(page)));
...@@ -604,9 +601,7 @@ btr_cur_open_at_rnd_pos( ...@@ -604,9 +601,7 @@ btr_cur_open_at_rnd_pos(
for (;;) { for (;;) {
page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL, page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
BUF_GET, BUF_GET,
#ifdef UNIV_SYNC_DEBUG
IB__FILE__, __LINE__, IB__FILE__, __LINE__,
#endif
mtr); mtr);
ut_ad(0 == ut_dulint_cmp(tree->id, ut_ad(0 == ut_dulint_cmp(tree->id,
btr_page_get_index_id(page))); btr_page_get_index_id(page)));
...@@ -1222,6 +1217,57 @@ btr_cur_parse_update_in_place( ...@@ -1222,6 +1217,57 @@ btr_cur_parse_update_in_place(
return(ptr); return(ptr);
} }
/*****************************************************************
Updates a secondary index record when the update causes no size
changes in its fields. The only case when this function is currently
called is that in a char field characters change to others which
are identified in the collation order. */
ulint
btr_cur_update_sec_rec_in_place(
/*============================*/
/* out: DB_SUCCESS or error number */
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 */
que_thr_t* thr, /* in: query thread */
mtr_t* mtr) /* in: mtr */
{
dict_index_t* index = cursor->index;
dict_index_t* clust_index;
ulint err;
rec_t* rec;
dulint roll_ptr = ut_dulint_zero;
trx_t* trx = thr_get_trx(thr);
/* Only secondary index records are updated using this function */
ut_ad(0 == (index->type & DICT_CLUSTERED));
rec = btr_cur_get_rec(cursor);
err = lock_sec_rec_modify_check_and_lock(0, rec, index, thr);
if (err != DB_SUCCESS) {
return(err);
}
/* Remove possible hash index pointer to this record */
btr_search_update_hash_on_delete(cursor);
row_upd_rec_in_place(rec, update);
clust_index = dict_table_get_first_index(index->table);
/* Note that roll_ptr is really just a dummy value since
a secondary index record does not contain any sys columns */
btr_cur_update_in_place_log(BTR_KEEP_SYS_FLAG, rec, clust_index,
update, trx, roll_ptr, mtr);
return(DB_SUCCESS);
}
/***************************************************************** /*****************************************************************
Updates a record when the update causes no size changes in its fields. */ Updates a record when the update causes no size changes in its fields. */
...@@ -1248,7 +1294,7 @@ btr_cur_update_in_place( ...@@ -1248,7 +1294,7 @@ btr_cur_update_in_place(
ibool was_delete_marked; ibool was_delete_marked;
/* Only clustered index records are updated using this function */ /* Only clustered index records are updated using this function */
ut_ad((cursor->index)->type & DICT_CLUSTERED); ut_ad(cursor->index->type & DICT_CLUSTERED);
rec = btr_cur_get_rec(cursor); rec = btr_cur_get_rec(cursor);
index = cursor->index; index = cursor->index;
...@@ -2477,27 +2523,33 @@ btr_estimate_n_rows_in_range( ...@@ -2477,27 +2523,33 @@ btr_estimate_n_rows_in_range(
} }
/*********************************************************************** /***********************************************************************
Estimates the number of different key values in a given index. */ Estimates the number of different key values in a given index, for
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
The estimates are stored in the array index->stat_n_diff_key_vals. */
ulint void
btr_estimate_number_of_different_key_vals( btr_estimate_number_of_different_key_vals(
/*======================================*/ /*======================================*/
/* out: estimated number of key values */
dict_index_t* index) /* in: index */ dict_index_t* index) /* in: index */
{ {
btr_cur_t cursor; btr_cur_t cursor;
page_t* page; page_t* page;
rec_t* rec; rec_t* rec;
ulint total_n_recs = 0; ulint n_cols;
ulint n_diff_in_page;
ulint n_diff = 0;
ulint matched_fields; ulint matched_fields;
ulint matched_bytes; ulint matched_bytes;
ulint* n_diff;
ulint not_empty_flag = 0;
ulint i; ulint i;
ulint j;
mtr_t mtr; mtr_t mtr;
if (index->type & DICT_UNIQUE) { n_cols = dict_index_get_n_unique(index);
return(index->table->stat_n_rows);
n_diff = mem_alloc((n_cols + 1) * sizeof(ib_longlong));
for (j = 0; j <= n_cols; j++) {
n_diff[j] = 0;
} }
/* We sample some pages in the index to get an estimate */ /* We sample some pages in the index to get an estimate */
...@@ -2507,17 +2559,19 @@ btr_estimate_number_of_different_key_vals( ...@@ -2507,17 +2559,19 @@ btr_estimate_number_of_different_key_vals(
btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr); btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
/* Count the number of different key values minus one on this /* Count the number of different key values minus one
index page: we subtract one because otherwise our algorithm for each prefix of the key on this index page: we subtract
would give a wrong estimate for an index where there is one because otherwise our algorithm would give a wrong
just one key value */ estimate for an index where there is just one key value */
page = btr_cur_get_page(&cursor); page = btr_cur_get_page(&cursor);
rec = page_get_infimum_rec(page); rec = page_get_infimum_rec(page);
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
n_diff_in_page = 0; if (rec != page_get_supremum_rec(page)) {
not_empty_flag = 1;
}
while (rec != page_get_supremum_rec(page) while (rec != page_get_supremum_rec(page)
&& page_rec_get_next(rec) && page_rec_get_next(rec)
...@@ -2528,30 +2582,30 @@ btr_estimate_number_of_different_key_vals( ...@@ -2528,30 +2582,30 @@ btr_estimate_number_of_different_key_vals(
cmp_rec_rec_with_match(rec, page_rec_get_next(rec), cmp_rec_rec_with_match(rec, page_rec_get_next(rec),
index, &matched_fields, index, &matched_fields,
&matched_bytes); &matched_bytes);
if (matched_fields <
dict_index_get_n_ordering_defined_by_user( for (j = matched_fields + 1; j <= n_cols; j++) {
index)) { n_diff[j]++;
n_diff_in_page++;
} }
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
} }
n_diff += n_diff_in_page;
total_n_recs += page_get_n_recs(page);
mtr_commit(&mtr); mtr_commit(&mtr);
} }
if (n_diff == 0) { /* If we saw k borders between different key values on
/* We play safe and assume that there are just two different BTR_KEY_VAL_ESTIMATE_N_PAGES leaf pages, we can estimate how many
key values in the index */ there will be in index->stat_n_leaf_pages */
return(2); for (j = 0; j <= n_cols; j++) {
index->stat_n_diff_key_vals[j] =
(n_diff[j] * index->stat_n_leaf_pages
+ BTR_KEY_VAL_ESTIMATE_N_PAGES - 1
+ not_empty_flag)
/ BTR_KEY_VAL_ESTIMATE_N_PAGES;
} }
return(index->table->stat_n_rows / (total_n_recs / n_diff)); mem_free(n_diff);
} }
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/ /*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
......
...@@ -62,8 +62,10 @@ btr_pcur_free_for_mysql( ...@@ -62,8 +62,10 @@ btr_pcur_free_for_mysql(
/****************************************************************** /******************************************************************
The position of the cursor is stored by taking an initial segment of the 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 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 cursor data structure, or just setting a flag if the cursor id before the
must not be empty! */ first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
page where the cursor is positioned must not be empty if the index tree is
not totally empty! */
void void
btr_pcur_store_position( btr_pcur_store_position(
...@@ -93,9 +95,21 @@ btr_pcur_store_position( ...@@ -93,9 +95,21 @@ btr_pcur_store_position(
ut_a(cursor->latch_mode != BTR_NO_LATCHES); ut_a(cursor->latch_mode != BTR_NO_LATCHES);
if (page_get_n_recs(page) == 0) { if (page_get_n_recs(page) == 0) {
/* It must be an empty index tree */
/* Cannot store position! */ ut_a(btr_page_get_next(page, mtr) == FIL_NULL
btr_pcur_close(cursor); && btr_page_get_prev(page, mtr) == FIL_NULL);
if (rec == page_get_supremum_rec(page)) {
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
cursor->old_stored = BTR_PCUR_OLD_STORED;
return;
}
cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
cursor->old_stored = BTR_PCUR_OLD_STORED;
return; return;
} }
...@@ -140,13 +154,15 @@ btr_pcur_copy_stored_position( ...@@ -140,13 +154,15 @@ btr_pcur_copy_stored_position(
ut_memcpy((byte*)pcur_receive, (byte*)pcur_donate, sizeof(btr_pcur_t)); ut_memcpy((byte*)pcur_receive, (byte*)pcur_donate, sizeof(btr_pcur_t));
if (pcur_donate->old_rec_buf) {
pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size); pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size);
ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf, ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
pcur_donate->buf_size); pcur_donate->buf_size);
pcur_receive->old_rec = pcur_receive->old_rec_buf pcur_receive->old_rec = pcur_receive->old_rec_buf
+ (pcur_donate->old_rec - pcur_donate->old_rec_buf); + (pcur_donate->old_rec - pcur_donate->old_rec_buf);
}
} }
/****************************************************************** /******************************************************************
...@@ -158,7 +174,9 @@ to the last record LESS OR EQUAL to the stored record; ...@@ -158,7 +174,9 @@ to the last record LESS OR EQUAL to the stored record;
the last record LESS than the user record which was the successor of the page the last record LESS than the user record which was the successor of the page
infimum; infimum;
(3) cursor was positioned on the page supremum: restores to the first record (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. */ GREATER than the user record which was the predecessor of the supremum.
(4) cursor was positioned before the first or after the last in an empty tree:
restores to before first or after the last in the tree. */
ibool ibool
btr_pcur_restore_position( btr_pcur_restore_position(
...@@ -177,17 +195,33 @@ btr_pcur_restore_position( ...@@ -177,17 +195,33 @@ btr_pcur_restore_position(
dtuple_t* tuple; dtuple_t* tuple;
ulint mode; ulint mode;
ulint old_mode; ulint old_mode;
ibool from_left;
mem_heap_t* heap; mem_heap_t* heap;
ut_a((cursor->pos_state == BTR_PCUR_WAS_POSITIONED) ut_a(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
|| (cursor->pos_state == BTR_PCUR_IS_POSITIONED)); || cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_a(cursor->old_stored == BTR_PCUR_OLD_STORED); ut_a(cursor->old_stored == BTR_PCUR_OLD_STORED);
if (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
if (cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
from_left = TRUE;
} else {
from_left = FALSE;
}
btr_cur_open_at_index_side(from_left,
btr_pcur_get_btr_cur(cursor)->index, latch_mode,
btr_pcur_get_btr_cur(cursor), mtr);
return(FALSE);
}
ut_a(cursor->old_rec); ut_a(cursor->old_rec);
page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor)); page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
if ((latch_mode == BTR_SEARCH_LEAF) if (latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF) {
|| (latch_mode == BTR_MODIFY_LEAF)) {
/* Try optimistic restoration */ /* Try optimistic restoration */
if (buf_page_optimistic_get(latch_mode, page, if (buf_page_optimistic_get(latch_mode, page,
...@@ -242,16 +276,15 @@ btr_pcur_restore_position( ...@@ -242,16 +276,15 @@ btr_pcur_restore_position(
/* Restore the old search mode */ /* Restore the old search mode */
cursor->search_mode = old_mode; cursor->search_mode = old_mode;
if ((cursor->rel_pos == BTR_PCUR_ON) if (cursor->rel_pos == BTR_PCUR_ON
&& btr_pcur_is_on_user_rec(cursor, mtr) && btr_pcur_is_on_user_rec(cursor, mtr)
&& (0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor)))) { && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor))) {
/* We have to store the NEW value for the modify clock, since /* We have to store the NEW value for the modify clock, since
the cursor can now be on a different page! */ the cursor can now be on a different page! */
cursor->modify_clock = buf_frame_get_modify_clock( cursor->modify_clock = buf_frame_get_modify_clock(
buf_frame_align( buf_frame_align(btr_pcur_get_rec(cursor)));
btr_pcur_get_rec(cursor)));
mem_heap_free(heap); mem_heap_free(heap);
return(TRUE); return(TRUE);
...@@ -366,6 +399,7 @@ btr_pcur_move_backward_from_page( ...@@ -366,6 +399,7 @@ btr_pcur_move_backward_from_page(
latch_mode2 = BTR_MODIFY_PREV; latch_mode2 = BTR_MODIFY_PREV;
} else { } else {
latch_mode2 = 0; /* To eliminate compiler warning */
ut_error; ut_error;
} }
......
...@@ -680,9 +680,7 @@ btr_search_guess_on_hash( ...@@ -680,9 +680,7 @@ btr_search_guess_on_hash(
success = buf_page_get_known_nowait(latch_mode, page, success = buf_page_get_known_nowait(latch_mode, page,
BUF_MAKE_YOUNG, BUF_MAKE_YOUNG,
#ifdef UNIV_SYNC_DEBUG
IB__FILE__, __LINE__, IB__FILE__, __LINE__,
#endif
mtr); mtr);
rw_lock_s_unlock(&btr_search_latch); rw_lock_s_unlock(&btr_search_latch);
......
This diff is collapsed.
...@@ -551,6 +551,10 @@ buf_LRU_block_free_non_file_page( ...@@ -551,6 +551,10 @@ buf_LRU_block_free_non_file_page(
block->state = BUF_BLOCK_NOT_USED; block->state = BUF_BLOCK_NOT_USED;
#ifdef UNIV_DEBUG
/* Wipe contents of page to reveal possible stale pointers to it */
memset(block->frame, '\0', UNIV_PAGE_SIZE);
#endif
UT_LIST_ADD_FIRST(free, buf_pool->free, block); UT_LIST_ADD_FIRST(free, buf_pool->free, block);
} }
......
...@@ -38,7 +38,7 @@ AC_CHECK_HEADERS(aio.h sched.h) ...@@ -38,7 +38,7 @@ AC_CHECK_HEADERS(aio.h sched.h)
AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(int, 4)
AC_CHECK_FUNCS(sched_yield) AC_CHECK_FUNCS(sched_yield)
AC_CHECK_FUNCS(fdatasync) AC_CHECK_FUNCS(fdatasync)
AC_CHECK_FUNCS(localtime_r) #AC_CHECK_FUNCS(localtime_r) # Already checked by MySQL
#AC_C_INLINE Already checked in MySQL #AC_C_INLINE Already checked in MySQL
AC_C_BIGENDIAN AC_C_BIGENDIAN
......
...@@ -14,6 +14,7 @@ Created 5/30/1994 Heikki Tuuri ...@@ -14,6 +14,7 @@ Created 5/30/1994 Heikki Tuuri
#include "ut0rnd.h" #include "ut0rnd.h"
#include "rem0rec.h" #include "rem0rec.h"
#include "rem0cmp.h"
#include "page0page.h" #include "page0page.h"
#include "dict0dict.h" #include "dict0dict.h"
#include "btr0cur.h" #include "btr0cur.h"
...@@ -63,6 +64,53 @@ dtuple_get_nth_field_noninline( ...@@ -63,6 +64,53 @@ dtuple_get_nth_field_noninline(
return(dtuple_get_nth_field(tuple, n)); return(dtuple_get_nth_field(tuple, n));
} }
/****************************************************************
Returns TRUE if lengths of two dtuples are equal and respective data fields
in them are equal when compared with collation in char fields (not as binary
strings). */
ibool
dtuple_datas_are_ordering_equal(
/*============================*/
/* out: TRUE if length and fieds are equal
when compared with cmp_data_data:
NOTE: in character type fields some letters
are identified with others! (collation) */
dtuple_t* tuple1, /* in: tuple 1 */
dtuple_t* tuple2) /* in: tuple 2 */
{
dfield_t* field1;
dfield_t* field2;
ulint n_fields;
ulint i;
ut_ad(tuple1 && tuple2);
ut_ad(tuple1->magic_n = DATA_TUPLE_MAGIC_N);
ut_ad(tuple2->magic_n = DATA_TUPLE_MAGIC_N);
ut_ad(dtuple_check_typed(tuple1));
ut_ad(dtuple_check_typed(tuple2));
n_fields = dtuple_get_n_fields(tuple1);
if (n_fields != dtuple_get_n_fields(tuple2)) {
return(FALSE);
}
for (i = 0; i < n_fields; i++) {
field1 = dtuple_get_nth_field(tuple1, i);
field2 = dtuple_get_nth_field(tuple2, i);
if (0 != cmp_dfield_dfield(field1, field2)) {
return(FALSE);
}
}
return(TRUE);
}
/************************************************************************* /*************************************************************************
Creates a dtuple for use in MySQL. */ Creates a dtuple for use in MySQL. */
...@@ -408,7 +456,7 @@ dtuple_convert_big_rec( ...@@ -408,7 +456,7 @@ dtuple_convert_big_rec(
ulint size; ulint size;
ulint n_fields; ulint n_fields;
ulint longest; ulint longest;
ulint longest_i; ulint longest_i = ULINT_MAX;
ibool is_externally_stored; ibool is_externally_stored;
ulint i; ulint i;
ulint j; ulint j;
......
...@@ -28,7 +28,6 @@ dtype_validate( ...@@ -28,7 +28,6 @@ dtype_validate(
ut_a((type->mtype >= DATA_VARCHAR) && (type->mtype <= DATA_MYSQL)); ut_a((type->mtype >= DATA_VARCHAR) && (type->mtype <= DATA_MYSQL));
if (type->mtype == DATA_SYS) { if (type->mtype == DATA_SYS) {
ut_a(type->prtype >= DATA_ROW_ID);
ut_a(type->prtype <= DATA_MIX_ID); ut_a(type->prtype <= DATA_MIX_ID);
} }
...@@ -45,11 +44,10 @@ dtype_print( ...@@ -45,11 +44,10 @@ dtype_print(
{ {
ulint mtype; ulint mtype;
ulint prtype; ulint prtype;
ulint len;
ut_a(type); ut_a(type);
printf("DATA TYPE: ");
mtype = type->mtype; mtype = type->mtype;
prtype = type->prtype; prtype = type->prtype;
if (mtype == DATA_VARCHAR) { if (mtype == DATA_VARCHAR) {
...@@ -65,17 +63,24 @@ dtype_print( ...@@ -65,17 +63,24 @@ dtype_print(
} else if (mtype == DATA_SYS) { } else if (mtype == DATA_SYS) {
printf("DATA_SYS"); printf("DATA_SYS");
} else { } else {
printf("unknown type %lu", mtype); printf("type %lu", mtype);
} }
len = type->len;
if ((type->mtype == DATA_SYS) if ((type->mtype == DATA_SYS)
|| (type->mtype == DATA_VARCHAR) || (type->mtype == DATA_VARCHAR)
|| (type->mtype == DATA_CHAR)) { || (type->mtype == DATA_CHAR)) {
printf(" "); printf(" ");
if (prtype == DATA_ROW_ID) { if (prtype == DATA_ROW_ID) {
printf("DATA_ROW_ID"); printf("DATA_ROW_ID");
len = DATA_ROW_ID_LEN;
} else if (prtype == DATA_ROLL_PTR) { } else if (prtype == DATA_ROLL_PTR) {
printf("DATA_ROLL_PTR"); printf("DATA_ROLL_PTR");
len = DATA_ROLL_PTR_LEN;
} else if (prtype == DATA_TRX_ID) {
printf("DATA_TRX_ID");
len = DATA_TRX_ID_LEN;
} else if (prtype == DATA_MIX_ID) { } else if (prtype == DATA_MIX_ID) {
printf("DATA_MIX_ID"); printf("DATA_MIX_ID");
} else if (prtype == DATA_ENGLISH) { } else if (prtype == DATA_ENGLISH) {
...@@ -83,9 +88,9 @@ dtype_print( ...@@ -83,9 +88,9 @@ dtype_print(
} else if (prtype == DATA_FINNISH) { } else if (prtype == DATA_FINNISH) {
printf("DATA_FINNISH"); printf("DATA_FINNISH");
} else { } else {
printf("unknown prtype %lu", mtype); printf("prtype %lu", mtype);
} }
} }
printf("; len %lu prec %lu\n", type->len, type->prec); printf(" len %lu prec %lu", len, type->prec);
} }
...@@ -17,9 +17,13 @@ Created 1/8/1996 Heikki Tuuri ...@@ -17,9 +17,13 @@ Created 1/8/1996 Heikki Tuuri
#include "page0page.h" #include "page0page.h"
#include "mach0data.h" #include "mach0data.h"
#include "dict0boot.h" #include "dict0boot.h"
#include "dict0dict.h"
#include "que0que.h" #include "que0que.h"
#include "row0ins.h" #include "row0ins.h"
#include "row0mysql.h"
#include "pars0pars.h" #include "pars0pars.h"
#include "trx0roll.h"
#include "usr0sess.h"
/********************************************************************* /*********************************************************************
Based on a table object, this function builds the entry to be inserted Based on a table object, this function builds the entry to be inserted
...@@ -1019,3 +1023,228 @@ function_exit: ...@@ -1019,3 +1023,228 @@ function_exit:
return(thr); return(thr);
} }
/********************************************************************
Creates the foreign key constraints system tables inside InnoDB
at database creation or database start if they are not found or are
not of the right form. */
ulint
dict_create_or_check_foreign_constraint_tables(void)
/*================================================*/
/* out: DB_SUCCESS or error code */
{
dict_table_t* table1;
dict_table_t* table2;
que_thr_t* thr;
que_t* graph;
ulint error;
trx_t* trx;
char* str;
mutex_enter(&(dict_sys->mutex));
table1 = dict_table_get_low("SYS_FOREIGN");
table2 = dict_table_get_low("SYS_FOREIGN_COLS");
if (table1 && table2
&& UT_LIST_GET_LEN(table1->indexes) == 3
&& UT_LIST_GET_LEN(table2->indexes) == 1) {
/* Foreign constraint system tables have already been
created, and they are ok */
mutex_exit(&(dict_sys->mutex));
return(DB_SUCCESS);
}
trx = trx_allocate_for_mysql();
trx->op_info = "creating foreign key sys tables";
if (table1) {
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN table\n");
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
}
if (table2) {
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN_COLS table\n");
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
}
fprintf(stderr,
"InnoDB: creating foreign key constraint system tables\n");
/* NOTE: in dict_load_foreigns we use the fact that
there are 2 secondary indexes on SYS_FOREIGN, and they
are defined just like below */
str =
"PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
"BEGIN\n"
"CREATE TABLE\n"
"SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT);\n"
"CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID);\n"
"CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME);\n"
"CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME);\n"
"CREATE TABLE\n"
"SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
"CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n"
"COMMIT WORK;\n"
"END;\n";
graph = pars_sql(str);
ut_a(graph);
graph->trx = trx;
trx->graph = NULL;
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
que_run_threads(thr);
error = trx->error_state;
if (error != DB_SUCCESS) {
ut_a(error == DB_OUT_OF_FILE_SPACE);
fprintf(stderr, "InnoDB: creation failed\n");
fprintf(stderr, "InnoDB: tablespace is full\n");
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN tables\n");
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
error = DB_MUST_GET_MORE_FILE_SPACE;
}
que_graph_free(graph);
trx->op_info = "";
trx_free_for_mysql(trx);
if (error == DB_SUCCESS) {
fprintf(stderr,
"InnoDB: foreign key constraint system tables created\n");
}
mutex_exit(&(dict_sys->mutex));
return(error);
}
/************************************************************************
Adds foreign key definitions to data dictionary tables in the database. */
ulint
dict_create_add_foreigns_to_dictionary(
/*===================================*/
/* out: error code or DB_SUCCESS */
dict_table_t* table, /* in: table */
trx_t* trx) /* in: transaction */
{
dict_foreign_t* foreign;
que_thr_t* thr;
que_t* graph;
dulint id;
ulint len;
ulint error;
ulint i;
char buf2[50];
char buf[10000];
ut_ad(mutex_own(&(dict_sys->mutex)));
if (NULL == dict_table_get_low("SYS_FOREIGN")) {
fprintf(stderr,
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
return(DB_ERROR);
}
foreign = UT_LIST_GET_FIRST(table->foreign_list);
loop:
if (foreign == NULL) {
return(DB_SUCCESS);
}
/* Build an InnoDB stored procedure which will insert the necessary
rows to SYS_FOREIGN and SYS_FOREIGN_COLS */
len = 0;
len += sprintf(buf,
"PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n"
"BEGIN\n");
/* We allocate the new id from the sequence of table id's */
id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
sprintf(buf2, "%lu_%lu", ut_dulint_get_high(id),
ut_dulint_get_low(id));
foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(buf2) + 1);
ut_memcpy(foreign->id, buf2, ut_strlen(buf2) + 1);
len += sprintf(buf + len,
"INSERT INTO SYS_FOREIGN VALUES('%lu_%lu', '%s', '%s', %lu);\n",
ut_dulint_get_high(id),
ut_dulint_get_low(id),
table->name,
foreign->referenced_table_name,
foreign->n_fields);
for (i = 0; i < foreign->n_fields; i++) {
len += sprintf(buf + len,
"INSERT INTO SYS_FOREIGN_COLS VALUES('%lu_%lu', %lu, '%s', '%s');\n",
ut_dulint_get_high(id),
ut_dulint_get_low(id),
i,
foreign->foreign_col_names[i],
foreign->referenced_col_names[i]);
}
len += sprintf(buf + len,"COMMIT WORK;\nEND;\n");
graph = pars_sql(buf);
ut_a(graph);
graph->trx = trx;
trx->graph = NULL;
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
que_run_threads(thr);
error = trx->error_state;
que_graph_free(graph);
if (error != DB_SUCCESS) {
ut_a(error == DB_OUT_OF_FILE_SPACE);
fprintf(stderr, "InnoDB: foreign constraint creation failed\n");
fprintf(stderr, "InnoDB: tablespace is full\n");
trx_general_rollback_for_mysql(trx, FALSE, NULL);
error = DB_MUST_GET_MORE_FILE_SPACE;
return(error);
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
goto loop;
}
This diff is collapsed.
This diff is collapsed.
...@@ -18,6 +18,7 @@ Created 1/8/1996 Heikki Tuuri ...@@ -18,6 +18,7 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0dict.h" #include "dict0dict.h"
#include "que0que.h" #include "que0que.h"
#include "pars0pars.h" #include "pars0pars.h"
#include "lock0lock.h"
#define DICT_HEAP_SIZE 100 /* initial memory heap size when #define DICT_HEAP_SIZE 100 /* initial memory heap size when
creating a table or index object */ creating a table or index object */
...@@ -63,7 +64,12 @@ dict_mem_table_create( ...@@ -63,7 +64,12 @@ dict_mem_table_create(
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS) table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t)); * sizeof(dict_col_t));
UT_LIST_INIT(table->indexes); UT_LIST_INIT(table->indexes);
table->auto_inc_lock = mem_heap_alloc(heap, lock_get_size());
UT_LIST_INIT(table->locks); UT_LIST_INIT(table->locks);
UT_LIST_INIT(table->foreign_list);
UT_LIST_INIT(table->referenced_list);
table->does_not_fit_in_memory = FALSE; table->does_not_fit_in_memory = FALSE;
...@@ -199,12 +205,49 @@ dict_mem_index_create( ...@@ -199,12 +205,49 @@ dict_mem_index_create(
* sizeof(dict_field_t)); * sizeof(dict_field_t));
/* The '1 +' above prevents allocation /* The '1 +' above prevents allocation
of an empty mem block */ of an empty mem block */
index->stat_n_diff_key_vals = NULL;
index->cached = FALSE; index->cached = FALSE;
index->magic_n = DICT_INDEX_MAGIC_N; index->magic_n = DICT_INDEX_MAGIC_N;
return(index); return(index);
} }
/**************************************************************************
Creates and initializes a foreign constraint memory object. */
dict_foreign_t*
dict_mem_foreign_create(void)
/*=========================*/
/* out, own: foreign constraint struct */
{
dict_foreign_t* foreign;
mem_heap_t* heap;
heap = mem_heap_create(100);
foreign = mem_heap_alloc(heap, sizeof(dict_foreign_t));
foreign->heap = heap;
foreign->id = NULL;
foreign->foreign_table_name = NULL;
foreign->foreign_table = NULL;
foreign->foreign_col_names = NULL;
foreign->referenced_table_name = NULL;
foreign->referenced_table = NULL;
foreign->referenced_col_names = NULL;
foreign->n_fields = 0;
foreign->foreign_index = NULL;
foreign->referenced_index = NULL;
return(foreign);
}
/************************************************************************** /**************************************************************************
Adds a field definition to an index. NOTE: does not take a copy Adds a field definition to an index. NOTE: does not take a copy
of the column name if the field is a column. The memory occupied of the column name if the field is a column. The memory occupied
......
...@@ -77,6 +77,9 @@ out of the LRU-list and keep a count of pending operations. When an operation ...@@ -77,6 +77,9 @@ out of the LRU-list and keep a count of pending operations. When an operation
completes, we decrement the count and return the file node to the LRU-list if completes, we decrement the count and return the file node to the LRU-list if
the count drops to zero. */ the count drops to zero. */
ulint fil_n_pending_log_flushes = 0;
ulint fil_n_pending_tablespace_flushes = 0;
/* Null file address */ /* Null file address */
fil_addr_t fil_addr_null = {FIL_NULL, 0}; fil_addr_t fil_addr_null = {FIL_NULL, 0};
...@@ -856,6 +859,15 @@ fil_node_prepare_for_io( ...@@ -856,6 +859,15 @@ fil_node_prepare_for_io(
last_node = UT_LIST_GET_LAST(system->LRU); last_node = UT_LIST_GET_LAST(system->LRU);
if (last_node == NULL) {
fprintf(stderr,
"InnoDB: Error: cannot close any file to open another for i/o\n"
"InnoDB: Pending i/o's on %lu files exist\n",
system->n_open_pending);
ut_a(0);
}
fil_node_close(last_node, system); fil_node_close(last_node, system);
} }
...@@ -973,6 +985,7 @@ fil_io( ...@@ -973,6 +985,7 @@ fil_io(
ibool ret; ibool ret;
ulint is_log; ulint is_log;
ulint wake_later; ulint wake_later;
ulint count;
is_log = type & OS_FILE_LOG; is_log = type & OS_FILE_LOG;
type = type & ~OS_FILE_LOG; type = type & ~OS_FILE_LOG;
...@@ -996,7 +1009,7 @@ fil_io( ...@@ -996,7 +1009,7 @@ fil_io(
#endif #endif
if (sync) { if (sync) {
mode = OS_AIO_SYNC; mode = OS_AIO_SYNC;
} else if ((type == OS_FILE_READ) && !is_log } else if (type == OS_FILE_READ && !is_log
&& ibuf_page(space_id, block_offset)) { && ibuf_page(space_id, block_offset)) {
mode = OS_AIO_IBUF; mode = OS_AIO_IBUF;
} else if (is_log) { } else if (is_log) {
...@@ -1006,9 +1019,44 @@ fil_io( ...@@ -1006,9 +1019,44 @@ fil_io(
} }
system = fil_system; system = fil_system;
count = 0;
loop: loop:
count++;
/* NOTE that there is a possibility of a hang here:
if the read i/o-handler thread needs to complete
a read by reading from the insert buffer, it may need to
post another read. But if the maximum number of files
are already open, it cannot proceed from here! */
mutex_enter(&(system->mutex)); mutex_enter(&(system->mutex));
if (count < 500 && !is_log && !ibuf_inside()
&& system->n_open_pending >= (3 * system->max_n_open) / 4) {
/* We are not doing an ibuf operation: leave a
safety margin of openable files for possible ibuf
merges needed in page read completion */
mutex_exit(&(system->mutex));
/* Wake the i/o-handler threads to make sure pending
i/o's are handled and eventually we can open the file */
os_aio_simulated_wake_handler_threads();
os_thread_sleep(100000);
if (count > 50) {
fprintf(stderr,
"InnoDB: Warning: waiting for file closes to proceed\n"
"InnoDB: round %lu\n", count);
}
goto loop;
}
if (system->n_open_pending == system->max_n_open) { if (system->n_open_pending == system->max_n_open) {
/* It is not sure we can open the file if it is closed: wait */ /* It is not sure we can open the file if it is closed: wait */
...@@ -1018,6 +1066,14 @@ loop: ...@@ -1018,6 +1066,14 @@ loop:
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
/* Wake the i/o-handler threads to make sure pending
i/o's are handled and eventually we can open the file */
os_aio_simulated_wake_handler_threads();
fprintf(stderr,
"InnoDB: Warning: max allowed number of files is open\n");
os_event_wait(event); os_event_wait(event);
goto loop; goto loop;
...@@ -1160,6 +1216,7 @@ fil_aio_wait( ...@@ -1160,6 +1216,7 @@ fil_aio_wait(
#elif defined(POSIX_ASYNC_IO) #elif defined(POSIX_ASYNC_IO)
ret = os_aio_posix_handle(segment, &fil_node, &message); ret = os_aio_posix_handle(segment, &fil_node, &message);
#else #else
ret = 0; /* Eliminate compiler warning */
ut_a(0); ut_a(0);
#endif #endif
} else { } else {
...@@ -1220,6 +1277,12 @@ fil_flush( ...@@ -1220,6 +1277,12 @@ fil_flush(
node->is_modified = FALSE; node->is_modified = FALSE;
if (space->purpose == FIL_TABLESPACE) {
fil_n_pending_tablespace_flushes++;
} else {
fil_n_pending_log_flushes++;
}
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
/* Note that it is not certain, when we have /* Note that it is not certain, when we have
...@@ -1233,6 +1296,12 @@ fil_flush( ...@@ -1233,6 +1296,12 @@ fil_flush(
os_file_flush(file); os_file_flush(file);
mutex_enter(&(system->mutex)); mutex_enter(&(system->mutex));
if (space->purpose == FIL_TABLESPACE) {
fil_n_pending_tablespace_flushes--;
} else {
fil_n_pending_log_flushes--;
}
} }
node = UT_LIST_GET_NEXT(chain, node); node = UT_LIST_GET_NEXT(chain, node);
...@@ -1377,7 +1446,7 @@ fil_page_set_type( ...@@ -1377,7 +1446,7 @@ fil_page_set_type(
ulint type) /* in: type */ ulint type) /* in: type */
{ {
ut_ad(page); ut_ad(page);
ut_ad((type == FIL_PAGE_INDEX) || (type == FIL_PAGE_INDEX)); ut_ad((type == FIL_PAGE_INDEX) || (type == FIL_PAGE_UNDO_LOG));
mach_write_to_2(page + FIL_PAGE_TYPE, type); mach_write_to_2(page + FIL_PAGE_TYPE, type);
} }
......
...@@ -1013,7 +1013,7 @@ ibuf_rec_get_volume( ...@@ -1013,7 +1013,7 @@ ibuf_rec_get_volume(
ulint i; ulint i;
ut_ad(ibuf_inside()); ut_ad(ibuf_inside());
ut_ad(rec_get_n_fields(rec) > 2); ut_ad(rec_get_n_fields(ibuf_rec) > 2);
n_fields = rec_get_n_fields(ibuf_rec) - 2; n_fields = rec_get_n_fields(ibuf_rec) - 2;
...@@ -1624,13 +1624,14 @@ ibuf_get_merge_page_nos( ...@@ -1624,13 +1624,14 @@ ibuf_get_merge_page_nos(
/************************************************************************* /*************************************************************************
Contracts insert buffer trees by reading pages to the buffer pool. */ Contracts insert buffer trees by reading pages to the buffer pool. */
static
ulint ulint
ibuf_contract( ibuf_contract_ext(
/*==========*/ /*==============*/
/* out: a lower limit for the combined size in bytes /* out: a lower limit for the combined size in bytes
of entries which will be merged from ibuf trees to the of entries which will be merged from ibuf trees to the
pages read, 0 if ibuf is empty */ pages read, 0 if ibuf is empty */
ulint* n_pages,/* out: number of pages to which merged */
ibool sync) /* in: TRUE if the caller wants to wait for the ibool sync) /* in: TRUE if the caller wants to wait for the
issued read with the highest tablespace address issued read with the highest tablespace address
to complete */ to complete */
...@@ -1644,6 +1645,8 @@ ibuf_contract( ...@@ -1644,6 +1645,8 @@ ibuf_contract(
ulint n_stored; ulint n_stored;
ulint sum_sizes; ulint sum_sizes;
mtr_t mtr; mtr_t mtr;
*n_pages = 0;
loop: loop:
ut_ad(!ibuf_inside()); ut_ad(!ibuf_inside());
...@@ -1730,9 +1733,64 @@ loop: ...@@ -1730,9 +1733,64 @@ loop:
buf_read_ibuf_merge_pages(sync, space, page_nos, n_stored); buf_read_ibuf_merge_pages(sync, space, page_nos, n_stored);
*n_pages = n_stored;
return(sum_sizes + 1); return(sum_sizes + 1);
} }
/*************************************************************************
Contracts insert buffer trees by reading pages to the buffer pool. */
ulint
ibuf_contract(
/*==========*/
/* out: a lower limit for the combined size in bytes
of entries which will be merged from ibuf trees to the
pages read, 0 if ibuf is empty */
ibool sync) /* in: TRUE if the caller wants to wait for the
issued read with the highest tablespace address
to complete */
{
ulint n_pages;
return(ibuf_contract_ext(&n_pages, sync));
}
/*************************************************************************
Contracts insert buffer trees by reading pages to the buffer pool. */
ulint
ibuf_contract_for_n_pages(
/*======================*/
/* out: a lower limit for the combined size in bytes
of entries which will be merged from ibuf trees to the
pages read, 0 if ibuf is empty */
ibool sync, /* in: TRUE if the caller wants to wait for the
issued read with the highest tablespace address
to complete */
ulint n_pages)/* in: try to read at least this many pages to
the buffer pool and merge the ibuf contents to
them */
{
ulint sum_bytes = 0;
ulint sum_pages = 0;
ulint n_bytes;
ulint n_pag2;
while (sum_pages < n_pages) {
n_bytes = ibuf_contract_ext(&n_pag2, sync);
if (n_bytes == 0) {
return(sum_bytes);
}
sum_bytes += n_bytes;
sum_pages += n_pag2;
}
return(sum_bytes);
}
/************************************************************************* /*************************************************************************
Contract insert buffer trees after insert if they are too big. */ Contract insert buffer trees after insert if they are too big. */
UNIV_INLINE UNIV_INLINE
...@@ -2253,8 +2311,6 @@ ibuf_insert_to_index_page( ...@@ -2253,8 +2311,6 @@ ibuf_insert_to_index_page(
if (low_match == dtuple_get_n_fields(entry)) { if (low_match == dtuple_get_n_fields(entry)) {
rec = page_cur_get_rec(&page_cur); rec = page_cur_get_rec(&page_cur);
ut_ad(rec_get_deleted_flag(rec));
btr_cur_del_unmark_for_ibuf(rec, mtr); btr_cur_del_unmark_for_ibuf(rec, mtr);
} else { } else {
rec = page_cur_tuple_insert(&page_cur, entry, mtr); rec = page_cur_tuple_insert(&page_cur, entry, mtr);
...@@ -2306,6 +2362,8 @@ ibuf_delete_rec( ...@@ -2306,6 +2362,8 @@ ibuf_delete_rec(
should belong */ should belong */
btr_pcur_t* pcur, /* in: pcur positioned on the record to btr_pcur_t* pcur, /* in: pcur positioned on the record to
delete, having latch mode BTR_MODIFY_LEAF */ delete, having latch mode BTR_MODIFY_LEAF */
dtuple_t* search_tuple,
/* in: search tuple for entries of page_no */
mtr_t* mtr) /* in: mtr */ mtr_t* mtr) /* in: mtr */
{ {
ibool success; ibool success;
...@@ -2336,7 +2394,28 @@ ibuf_delete_rec( ...@@ -2336,7 +2394,28 @@ ibuf_delete_rec(
mtr_start(mtr); mtr_start(mtr);
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr);
if (!success) {
fprintf(stderr,
"InnoDB: ERROR: Send the output to heikki.tuuri@innodb.com\n");
fprintf(stderr, "InnoDB: ibuf cursor restoration fails!\n");
fprintf(stderr, "InnoDB: ibuf record inserted to page %lu\n",
page_no);
rec_print(btr_pcur_get_rec(pcur));
rec_print(pcur->old_rec);
dtuple_print(search_tuple);
rec_print(page_rec_get_next(btr_pcur_get_rec(pcur)));
mtr_commit(mtr);
fprintf(stderr, "InnoDB: Validating insert buffer tree:\n");
ut_a(btr_validate_tree(ibuf_data->index->tree));
fprintf(stderr, "InnoDB: Ibuf tree ok\n");
}
ut_a(success);
root = ibuf_tree_root_get(ibuf_data, space, mtr); root = ibuf_tree_root_get(ibuf_data, space, mtr);
...@@ -2393,7 +2472,10 @@ ibuf_merge_or_delete_for_page( ...@@ -2393,7 +2472,10 @@ ibuf_merge_or_delete_for_page(
dulint max_trx_id; dulint max_trx_id;
mtr_t mtr; mtr_t mtr;
/* TODO: get MySQL type info to use in ibuf_insert_to_index_page */ if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
return;
}
#ifdef UNIV_LOG_DEBUG #ifdef UNIV_LOG_DEBUG
if (space % 2 != 0) { if (space % 2 != 0) {
...@@ -2451,11 +2533,8 @@ loop: ...@@ -2451,11 +2533,8 @@ loop:
if (page) { if (page) {
success = buf_page_get_known_nowait(RW_X_LATCH, page, success = buf_page_get_known_nowait(RW_X_LATCH, page,
BUF_KEEP_OLD, BUF_KEEP_OLD,
#ifdef UNIV_SYNC_DEBUG
IB__FILE__, __LINE__, IB__FILE__, __LINE__,
#endif
&mtr); &mtr);
ut_a(success); ut_a(success);
buf_page_dbg_add_level(page, SYNC_TREE_NODE); buf_page_dbg_add_level(page, SYNC_TREE_NODE);
...@@ -2508,13 +2587,13 @@ loop: ...@@ -2508,13 +2587,13 @@ loop:
/ IBUF_PAGE_SIZE_PER_FREE_SPACE); / IBUF_PAGE_SIZE_PER_FREE_SPACE);
#endif #endif
ibuf_insert_to_index_page(entry, page, &mtr); ibuf_insert_to_index_page(entry, page, &mtr);
}
n_inserts++; n_inserts++;
}
/* Delete the record from ibuf */ /* Delete the record from ibuf */
closed = ibuf_delete_rec(space, page_no, &pcur, &mtr); closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
&mtr);
if (closed) { if (closed) {
/* Deletion was pessimistic and mtr was committed: /* Deletion was pessimistic and mtr was committed:
we start from the beginning again */ we start from the beginning again */
...@@ -2524,6 +2603,7 @@ loop: ...@@ -2524,6 +2603,7 @@ loop:
if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) { if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) {
mtr_commit(&mtr); mtr_commit(&mtr);
btr_pcur_close(&pcur);
goto loop; goto loop;
} }
...@@ -2619,8 +2699,6 @@ ibuf_print(void) ...@@ -2619,8 +2699,6 @@ ibuf_print(void)
#endif #endif
mutex_enter(&ibuf_mutex); mutex_enter(&ibuf_mutex);
printf("Ibuf size %lu max size %lu\n", ibuf->size, ibuf->max_size);
data = UT_LIST_GET_FIRST(ibuf->data_list); data = UT_LIST_GET_FIRST(ibuf->data_list);
while (data) { while (data) {
......
...@@ -188,6 +188,22 @@ btr_cur_pessimistic_insert( ...@@ -188,6 +188,22 @@ btr_cur_pessimistic_insert(
que_thr_t* thr, /* in: query thread or NULL */ que_thr_t* thr, /* in: query thread or NULL */
mtr_t* mtr); /* in: mtr */ mtr_t* mtr); /* in: mtr */
/***************************************************************** /*****************************************************************
Updates a secondary index record when the update causes no size
changes in its fields. The only case when this function is currently
called is that in a char field characters change to others which
are identified in the collation order. */
ulint
btr_cur_update_sec_rec_in_place(
/*============================*/
/* out: DB_SUCCESS or error number */
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 */
que_thr_t* thr, /* in: query thread */
mtr_t* mtr); /* in: mtr */
/*****************************************************************
Updates a record when the update causes no size changes in its fields. */ Updates a record when the update causes no size changes in its fields. */
ulint ulint
...@@ -411,12 +427,13 @@ btr_estimate_n_rows_in_range( ...@@ -411,12 +427,13 @@ btr_estimate_n_rows_in_range(
dtuple_t* tuple2, /* in: range end, may also be empty tuple */ dtuple_t* tuple2, /* in: range end, may also be empty tuple */
ulint mode2); /* in: search mode for range end */ ulint mode2); /* in: search mode for range end */
/*********************************************************************** /***********************************************************************
Estimates the number of different key values in a given index. */ Estimates the number of different key values in a given index, for
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
The estimates are stored in the array index->stat_n_diff_key_vals. */
ulint void
btr_estimate_number_of_different_key_vals( btr_estimate_number_of_different_key_vals(
/*======================================*/ /*======================================*/
/* out: estimated number of key values */
dict_index_t* index); /* in: index */ dict_index_t* index); /* in: index */
/*********************************************************************** /***********************************************************************
Marks not updated extern fields as not-owned by this record. The ownership Marks not updated extern fields as not-owned by this record. The ownership
......
...@@ -22,6 +22,12 @@ Created 2/23/1996 Heikki Tuuri ...@@ -22,6 +22,12 @@ Created 2/23/1996 Heikki Tuuri
#define BTR_PCUR_ON 1 #define BTR_PCUR_ON 1
#define BTR_PCUR_BEFORE 2 #define BTR_PCUR_BEFORE 2
#define BTR_PCUR_AFTER 3 #define BTR_PCUR_AFTER 3
/* Note that if the tree is not empty, btr_pcur_store_position does not
use the following, but only uses the above three alternatives, where the
position is stored relative to a specific record: this makes implementation
of a scroll cursor easier */
#define BTR_PCUR_BEFORE_FIRST_IN_TREE 4 /* in an empty tree */
#define BTR_PCUR_AFTER_LAST_IN_TREE 5 /* in an empty tree */
/****************************************************************** /******************************************************************
Allocates memory for a persistent cursor object and initializes the cursor. */ Allocates memory for a persistent cursor object and initializes the cursor. */
...@@ -170,8 +176,10 @@ btr_pcur_close( ...@@ -170,8 +176,10 @@ btr_pcur_close(
/****************************************************************** /******************************************************************
The position of the cursor is stored by taking an initial segment of the 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 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 cursor data structure, or just setting a flag if the cursor id before the
must not be empty! */ first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
page where the cursor is positioned must not be empty if the index tree is
not totally empty! */
void void
btr_pcur_store_position( btr_pcur_store_position(
...@@ -179,26 +187,6 @@ btr_pcur_store_position( ...@@ -179,26 +187,6 @@ btr_pcur_store_position(
btr_pcur_t* cursor, /* in: persistent cursor */ btr_pcur_t* cursor, /* in: persistent cursor */
mtr_t* mtr); /* in: mtr */ mtr_t* mtr); /* in: mtr */
/****************************************************************** /******************************************************************
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 */
/*************************************************************
Gets the rel_pos field for a cursor whose position has been stored. */
UNIV_INLINE
ulint
btr_pcur_get_rel_pos(
/*=================*/
/* out: BTR_PCUR_ON, ... */
btr_pcur_t* cursor);/* in: persistent cursor */
/******************************************************************
Restores the stored position of a persistent cursor bufferfixing the page and Restores the stored position of a persistent cursor bufferfixing the page and
obtaining the specified latches. If the cursor position was saved when the 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 (1) cursor was positioned on a user record: this function restores the position
...@@ -207,7 +195,9 @@ to the last record LESS OR EQUAL to the stored record; ...@@ -207,7 +195,9 @@ to the last record LESS OR EQUAL to the stored record;
the last record LESS than the user record which was the successor of the page the last record LESS than the user record which was the successor of the page
infimum; infimum;
(3) cursor was positioned on the page supremum: restores to the first record (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. */ GREATER than the user record which was the predecessor of the supremum.
(4) cursor was positioned before the first or after the last in an empty tree:
restores to before first or after the last in the tree. */
ibool ibool
btr_pcur_restore_position( btr_pcur_restore_position(
...@@ -220,6 +210,26 @@ btr_pcur_restore_position( ...@@ -220,6 +210,26 @@ btr_pcur_restore_position(
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */ ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
btr_pcur_t* cursor, /* in: detached persistent cursor */ btr_pcur_t* cursor, /* in: detached persistent cursor */
mtr_t* mtr); /* in: mtr */ mtr_t* mtr); /* in: mtr */
/******************************************************************
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 */
/*************************************************************
Gets the rel_pos field for a cursor whose position has been stored. */
UNIV_INLINE
ulint
btr_pcur_get_rel_pos(
/*=================*/
/* out: BTR_PCUR_ON, ... */
btr_pcur_t* cursor);/* in: persistent cursor */
/************************************************************* /*************************************************************
Sets the mtr field for a pcur. */ Sets the mtr field for a pcur. */
UNIV_INLINE UNIV_INLINE
...@@ -458,7 +468,7 @@ struct btr_pcur_struct{ ...@@ -458,7 +468,7 @@ struct btr_pcur_struct{
ulint search_mode; /* PAGE_CUR_G, ... */ ulint search_mode; /* PAGE_CUR_G, ... */
/*-----------------------------*/ /*-----------------------------*/
/* NOTE that the following fields may possess dynamically allocated /* NOTE that the following fields may possess dynamically allocated
memory, which should be freed if not needed anymore! */ memory which should be freed if not needed anymore! */
mtr_t* mtr; /* NULL, or this field may contain mtr_t* mtr; /* NULL, or this field may contain
a mini-transaction which holds the a mini-transaction which holds the
......
...@@ -19,8 +19,8 @@ btr_pcur_get_rel_pos( ...@@ -19,8 +19,8 @@ btr_pcur_get_rel_pos(
ut_ad(cursor); ut_ad(cursor);
ut_ad(cursor->old_rec); ut_ad(cursor->old_rec);
ut_ad(cursor->old_stored == BTR_PCUR_OLD_STORED); ut_ad(cursor->old_stored == BTR_PCUR_OLD_STORED);
ut_ad((cursor->pos_state == BTR_PCUR_WAS_POSITIONED) ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
|| (cursor->pos_state == BTR_PCUR_IS_POSITIONED)); || cursor->pos_state == BTR_PCUR_IS_POSITIONED);
return(cursor->rel_pos); return(cursor->rel_pos);
} }
......
...@@ -262,6 +262,12 @@ index */ ...@@ -262,6 +262,12 @@ index */
#define BTR_SEARCH_ON_HASH_LIMIT 3 #define BTR_SEARCH_ON_HASH_LIMIT 3
/* We do this many searches before trying to keep the search latch over calls
from MySQL. If we notice someone waiting for the latch, we again set this
much timeout. This is to reduce contention. */
#define BTR_SEA_TIMEOUT 10000
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "btr0sea.ic" #include "btr0sea.ic"
#endif #endif
......
...@@ -116,53 +116,30 @@ buf_frame_copy( ...@@ -116,53 +116,30 @@ buf_frame_copy(
NOTE! The following macros should be used instead of buf_page_get_gen, NOTE! The following macros should be used instead of buf_page_get_gen,
to improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed to improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed
in LA! */ in LA! */
#ifdef UNIV_SYNC_DEBUG
#define buf_page_get(SP, OF, LA, MTR) buf_page_get_gen(\ #define buf_page_get(SP, OF, LA, MTR) buf_page_get_gen(\
SP, OF, LA, NULL,\ SP, OF, LA, NULL,\
BUF_GET, IB__FILE__, __LINE__, MTR) BUF_GET, IB__FILE__, __LINE__, MTR)
#else
#define buf_page_get(SP, OF, LA, MTR) buf_page_get_gen(\
SP, OF, LA, NULL,\
BUF_GET, MTR)
#endif
/****************************************************************** /******************************************************************
Use these macros to bufferfix a page with no latching. Remember not to Use these macros to bufferfix a page with no latching. Remember not to
read the contents of the page unless you know it is safe. Do not modify read the contents of the page unless you know it is safe. Do not modify
the contents of the page! We have separated this case, because it is the contents of the page! We have separated this case, because it is
error-prone programming not to set a latch, and it should be used error-prone programming not to set a latch, and it should be used
with care. */ with care. */
#ifdef UNIV_SYNC_DEBUG
#define buf_page_get_with_no_latch(SP, OF, MTR) buf_page_get_gen(\ #define buf_page_get_with_no_latch(SP, OF, MTR) buf_page_get_gen(\
SP, OF, RW_NO_LATCH, NULL,\ SP, OF, RW_NO_LATCH, NULL,\
BUF_GET_NO_LATCH, IB__FILE__, __LINE__, MTR) BUF_GET_NO_LATCH, IB__FILE__, __LINE__, MTR)
#else
#define buf_page_get_with_no_latch(SP, OF, MTR) buf_page_get_gen(\
SP, OF, RW_NO_LATCH, NULL,\
BUF_GET_NO_LATCH, MTR)
#endif
/****************************************************************** /******************************************************************
NOTE! The following macros should be used instead of buf_page_get_gen, to NOTE! The following macros should be used instead of buf_page_get_gen, to
improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed as LA! */ improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed as LA! */
#ifdef UNIV_SYNC_DEBUG
#define buf_page_get_nowait(SP, OF, LA, MTR) buf_page_get_gen(\ #define buf_page_get_nowait(SP, OF, LA, MTR) buf_page_get_gen(\
SP, OF, LA, NULL,\ SP, OF, LA, NULL,\
BUF_GET_NOWAIT, IB__FILE__, __LINE__, MTR) BUF_GET_NOWAIT, IB__FILE__, __LINE__, MTR)
#else
#define buf_page_get_nowait(SP, OF, LA, MTR) buf_page_get_gen(\
SP, OF, LA, NULL,\
BUF_GET_NOWAIT, MTR)
#endif
/****************************************************************** /******************************************************************
NOTE! The following macros should be used instead of NOTE! The following macros should be used instead of
buf_page_optimistic_get_func, to improve debugging. Only values RW_S_LATCH and buf_page_optimistic_get_func, to improve debugging. Only values RW_S_LATCH and
RW_X_LATCH are allowed as LA! */ RW_X_LATCH are allowed as LA! */
#ifdef UNIV_SYNC_DEBUG
#define buf_page_optimistic_get(LA, G, MC, MTR) buf_page_optimistic_get_func(\ #define buf_page_optimistic_get(LA, G, MC, MTR) buf_page_optimistic_get_func(\
LA, G, MC, IB__FILE__, __LINE__, MTR) LA, G, MC, IB__FILE__, __LINE__, MTR)
#else
#define buf_page_optimistic_get(LA, G, MC, MTR) buf_page_optimistic_get_func(\
LA, G, MC, MTR)
#endif
/************************************************************************ /************************************************************************
This is the general function used to get optimistic access to a database This is the general function used to get optimistic access to a database
page. */ page. */
...@@ -175,10 +152,8 @@ buf_page_optimistic_get_func( ...@@ -175,10 +152,8 @@ buf_page_optimistic_get_func(
buf_frame_t* guess, /* in: guessed frame */ buf_frame_t* guess, /* in: guessed frame */
dulint modify_clock,/* in: modify clock value if mode is dulint modify_clock,/* in: modify clock value if mode is
..._GUESS_ON_CLOCK */ ..._GUESS_ON_CLOCK */
#ifdef UNIV_SYNC_DEBUG
char* file, /* in: file name */ char* file, /* in: file name */
ulint line, /* in: line where called */ ulint line, /* in: line where called */
#endif
mtr_t* mtr); /* in: mini-transaction */ mtr_t* mtr); /* in: mini-transaction */
/************************************************************************ /************************************************************************
Tries to get the page, but if file io is required, releases all latches Tries to get the page, but if file io is required, releases all latches
...@@ -210,10 +185,8 @@ buf_page_get_known_nowait( ...@@ -210,10 +185,8 @@ buf_page_get_known_nowait(
ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */ ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
buf_frame_t* guess, /* in: the known page frame */ buf_frame_t* guess, /* in: the known page frame */
ulint mode, /* in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */ ulint mode, /* in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
#ifdef UNIV_SYNC_DEBUG
char* file, /* in: file name */ char* file, /* in: file name */
ulint line, /* in: line where called */ ulint line, /* in: line where called */
#endif
mtr_t* mtr); /* in: mini-transaction */ mtr_t* mtr); /* in: mini-transaction */
/************************************************************************ /************************************************************************
This is the general function used to get access to a database page. */ This is the general function used to get access to a database page. */
...@@ -228,10 +201,8 @@ buf_page_get_gen( ...@@ -228,10 +201,8 @@ buf_page_get_gen(
buf_frame_t* guess, /* in: guessed frame or NULL */ buf_frame_t* guess, /* in: guessed frame or NULL */
ulint mode, /* in: BUF_GET, BUF_GET_IF_IN_POOL, ulint mode, /* in: BUF_GET, BUF_GET_IF_IN_POOL,
BUF_GET_NO_LATCH */ BUF_GET_NO_LATCH */
#ifdef UNIV_SYNC_DEBUG
char* file, /* in: file name */ char* file, /* in: file name */
ulint line, /* in: line where called */ ulint line, /* in: line where called */
#endif
mtr_t* mtr); /* in: mini-transaction */ mtr_t* mtr); /* in: mini-transaction */
/************************************************************************ /************************************************************************
Initializes a page to the buffer buf_pool. The page is usually not read Initializes a page to the buffer buf_pool. The page is usually not read
...@@ -455,6 +426,13 @@ Validates the buffer pool data structure. */ ...@@ -455,6 +426,13 @@ Validates the buffer pool data structure. */
ibool ibool
buf_validate(void); buf_validate(void);
/*==============*/ /*==============*/
/************************************************************************
Prints a page to stderr. */
void
buf_page_print(
/*===========*/
byte* read_buf); /* in: a database page */
/************************************************************************* /*************************************************************************
Prints info of the buffer pool data structure. */ Prints info of the buffer pool data structure. */
...@@ -462,6 +440,12 @@ void ...@@ -462,6 +440,12 @@ void
buf_print(void); buf_print(void);
/*===========*/ /*===========*/
/************************************************************************* /*************************************************************************
Returns the number of pending buf pool ios. */
ulint
buf_get_n_pending_ios(void);
/*=======================*/
/*************************************************************************
Prints info of the buffer i/o. */ Prints info of the buffer i/o. */
void void
...@@ -760,6 +744,8 @@ struct buf_pool_struct{ ...@@ -760,6 +744,8 @@ struct buf_pool_struct{
byte* frame_zero; /* pointer to the first buffer frame: byte* frame_zero; /* pointer to the first buffer frame:
this may differ from frame_mem, because this may differ from frame_mem, because
this is aligned by the frame size */ this is aligned by the frame size */
byte* high_end; /* pointer to the end of the
buffer pool */
buf_block_t* blocks; /* array of buffer control blocks */ buf_block_t* blocks; /* array of buffer control blocks */
ulint max_size; /* number of control blocks == ulint max_size; /* number of control blocks ==
maximum pool size in pages */ maximum pool size in pages */
...@@ -767,6 +753,9 @@ struct buf_pool_struct{ ...@@ -767,6 +753,9 @@ struct buf_pool_struct{
hash_table_t* page_hash; /* hash table of the file pages */ hash_table_t* page_hash; /* hash table of the file pages */
ulint n_pend_reads; /* number of pending read operations */ ulint n_pend_reads; /* number of pending read operations */
time_t last_printout_time; /* when buf_print was last time
called */
ulint n_pages_read; /* number read operations */ ulint n_pages_read; /* number read operations */
ulint n_pages_written;/* number write operations */ ulint n_pages_written;/* number write operations */
ulint n_pages_created;/* number of pages created in the pool ulint n_pages_created;/* number of pages created in the pool
...@@ -782,6 +771,9 @@ struct buf_pool_struct{ ...@@ -782,6 +771,9 @@ struct buf_pool_struct{
hit rate */ hit rate */
ulint n_pages_read_old;/* n_pages_read when buf_print was ulint n_pages_read_old;/* n_pages_read when buf_print was
last time called */ last time called */
ulint n_pages_written_old;/* number write operations */
ulint n_pages_created_old;/* number of pages created in
the pool with no read */
/* 2. Page flushing algorithm fields */ /* 2. Page flushing algorithm fields */
UT_LIST_BASE_NODE_T(buf_block_t) flush_list; UT_LIST_BASE_NODE_T(buf_block_t) flush_list;
......
...@@ -486,11 +486,7 @@ buf_block_buf_fix_inc_debug( ...@@ -486,11 +486,7 @@ buf_block_buf_fix_inc_debug(
{ {
ibool ret; ibool ret;
ret = rw_lock_s_lock_func_nowait(&(block->debug_latch) ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line);
#ifdef UNIV_SYNC_DEBUG
,file, line
#endif
);
ut_ad(ret == TRUE); ut_ad(ret == TRUE);
...@@ -557,9 +553,7 @@ buf_page_get_release_on_io( ...@@ -557,9 +553,7 @@ buf_page_get_release_on_io(
frame = buf_page_get_gen(space, offset, rw_latch, guess, frame = buf_page_get_gen(space, offset, rw_latch, guess,
BUF_GET_IF_IN_POOL, BUF_GET_IF_IN_POOL,
#ifdef UNIV_SYNC_DEBUG
IB__FILE__, __LINE__, IB__FILE__, __LINE__,
#endif
mtr); mtr);
if (frame != NULL) { if (frame != NULL) {
......
...@@ -116,8 +116,8 @@ dfield_copy( ...@@ -116,8 +116,8 @@ dfield_copy(
Tests if data length and content is equal for two dfields. */ Tests if data length and content is equal for two dfields. */
UNIV_INLINE UNIV_INLINE
ibool ibool
dfield_datas_are_equal( dfield_datas_are_binary_equal(
/*===================*/ /*==========================*/
/* out: TRUE if equal */ /* out: TRUE if equal */
dfield_t* field1, /* in: field */ dfield_t* field1, /* in: field */
dfield_t* field2);/* in: field */ dfield_t* field2);/* in: field */
...@@ -125,8 +125,8 @@ dfield_datas_are_equal( ...@@ -125,8 +125,8 @@ dfield_datas_are_equal(
Tests if dfield data length and content is equal to the given. */ Tests if dfield data length and content is equal to the given. */
UNIV_INLINE UNIV_INLINE
ibool ibool
dfield_data_is_equal( dfield_data_is_binary_equal(
/*=================*/ /*========================*/
/* out: TRUE if equal */ /* out: TRUE if equal */
dfield_t* field, /* in: field */ dfield_t* field, /* in: field */
ulint len, /* in: data length or UNIV_SQL_NULL */ ulint len, /* in: data length or UNIV_SQL_NULL */
...@@ -230,14 +230,18 @@ dtuple_get_data_size( ...@@ -230,14 +230,18 @@ dtuple_get_data_size(
dtuple_t* tuple); /* in: typed data tuple */ dtuple_t* tuple); /* in: typed data tuple */
/**************************************************************** /****************************************************************
Returns TRUE if lengths of two dtuples are equal and respective data fields Returns TRUE if lengths of two dtuples are equal and respective data fields
in them are equal. */ in them are equal when compared with collation in char fields (not as binary
UNIV_INLINE strings). */
ibool ibool
dtuple_datas_are_equal( dtuple_datas_are_ordering_equal(
/*===================*/ /*============================*/
/* out: TRUE if length and datas are equal */ /* out: TRUE if length and fieds are equal
when compared with cmp_data_data:
NOTE: in character type fields some letters
are identified with others! (collation) */
dtuple_t* tuple1, /* in: tuple 1 */ dtuple_t* tuple1, /* in: tuple 1 */
dtuple_t* tuple2); /* in: tuple 2 */ dtuple_t* tuple2);/* in: tuple 2 */
/**************************************************************** /****************************************************************
Folds a prefix given as the number of fields of a tuple. */ Folds a prefix given as the number of fields of a tuple. */
UNIV_INLINE UNIV_INLINE
...@@ -447,7 +451,7 @@ struct dfield_struct{ ...@@ -447,7 +451,7 @@ struct dfield_struct{
struct dtuple_struct { struct dtuple_struct {
ulint info_bits; /* info bits of an index record: ulint info_bits; /* info bits of an index record:
default is 0; this field is used the default is 0; this field is used
if an index record is built from if an index record is built from
a data tuple */ a data tuple */
ulint n_fields; /* number of fields in dtuple */ ulint n_fields; /* number of fields in dtuple */
......
...@@ -133,8 +133,8 @@ dfield_copy( ...@@ -133,8 +133,8 @@ dfield_copy(
Tests if data length and content is equal for two dfields. */ Tests if data length and content is equal for two dfields. */
UNIV_INLINE UNIV_INLINE
ibool ibool
dfield_datas_are_equal( dfield_datas_are_binary_equal(
/*===================*/ /*==========================*/
/* out: TRUE if equal */ /* out: TRUE if equal */
dfield_t* field1, /* in: field */ dfield_t* field1, /* in: field */
dfield_t* field2) /* in: field */ dfield_t* field2) /* in: field */
...@@ -157,8 +157,8 @@ dfield_datas_are_equal( ...@@ -157,8 +157,8 @@ dfield_datas_are_equal(
Tests if dfield data length and content is equal to the given. */ Tests if dfield data length and content is equal to the given. */
UNIV_INLINE UNIV_INLINE
ibool ibool
dfield_data_is_equal( dfield_data_is_binary_equal(
/*=================*/ /*========================*/
/* out: TRUE if equal */ /* out: TRUE if equal */
dfield_t* field, /* in: field */ dfield_t* field, /* in: field */
ulint len, /* in: data length or UNIV_SQL_NULL */ ulint len, /* in: data length or UNIV_SQL_NULL */
...@@ -169,8 +169,7 @@ dfield_data_is_equal( ...@@ -169,8 +169,7 @@ dfield_data_is_equal(
return(FALSE); return(FALSE);
} }
if ((len != UNIV_SQL_NULL) if (len != UNIV_SQL_NULL && 0 != ut_memcmp(field->data, data, len)) {
&& (0 != ut_memcmp(field->data, data, len))) {
return(FALSE); return(FALSE);
} }
...@@ -342,65 +341,6 @@ dtuple_get_data_size( ...@@ -342,65 +341,6 @@ dtuple_get_data_size(
return(sum); return(sum);
} }
/****************************************************************
Returns TRUE if lengths of two dtuples are equal and respective data fields
in them are equal. */
UNIV_INLINE
ibool
dtuple_datas_are_equal(
/*===================*/
/* out: TRUE if length and datas are equal */
dtuple_t* tuple1, /* in: tuple 1 */
dtuple_t* tuple2) /* in: tuple 2 */
{
dfield_t* field1;
dfield_t* field2;
ulint n_fields;
byte* data1;
byte* data2;
ulint len1;
ulint len2;
ulint i;
ut_ad(tuple1 && tuple2);
ut_ad(tuple1->magic_n = DATA_TUPLE_MAGIC_N);
ut_ad(tuple2->magic_n = DATA_TUPLE_MAGIC_N);
ut_ad(dtuple_check_typed(tuple1));
ut_ad(dtuple_check_typed(tuple2));
n_fields = dtuple_get_n_fields(tuple1);
if (n_fields != dtuple_get_n_fields(tuple2)) {
return(FALSE);
}
for (i = 0; i < n_fields; i++) {
field1 = dtuple_get_nth_field(tuple1, i);
data1 = (byte*) dfield_get_data(field1);
len1 = dfield_get_len(field1);
field2 = dtuple_get_nth_field(tuple2, i);
data2 = (byte*) dfield_get_data(field2);
len2 = dfield_get_len(field2);
if (len1 != len2) {
return(FALSE);
}
if (len1 != UNIV_SQL_NULL) {
if (ut_memcmp(data1, data2, len1) != 0) {
return(FALSE);
}
}
}
return(TRUE);
}
/*********************************************************************** /***********************************************************************
Sets types of fields binary in a tuple. */ Sets types of fields binary in a tuple. */
UNIV_INLINE UNIV_INLINE
......
...@@ -124,17 +124,6 @@ dtype_get_pad_char( ...@@ -124,17 +124,6 @@ dtype_get_pad_char(
/* out: padding character code, or /* out: padding character code, or
ULINT_UNDEFINED if no padding specified */ ULINT_UNDEFINED if no padding specified */
dtype_t* type); /* in: typeumn */ dtype_t* type); /* in: typeumn */
/*************************************************************************
Transforms the character code so that it is ordered appropriately
for the language. */
UNIV_INLINE
ulint
dtype_collate(
/*==========*/
/* out: padding character */
dtype_t* type, /* in: type */
ulint code); /* in: character code stored in database
record */
/*************************************************************************** /***************************************************************************
Returns the size of a fixed size data type, 0 if not a fixed size type. */ Returns the size of a fixed size data type, 0 if not a fixed size type. */
UNIV_INLINE UNIV_INLINE
......
...@@ -120,23 +120,6 @@ dtype_get_pad_char( ...@@ -120,23 +120,6 @@ dtype_get_pad_char(
return(ULINT_UNDEFINED); return(ULINT_UNDEFINED);
} }
/*************************************************************************
Transforms the character code so that it is ordered appropriately for the
language. */
UNIV_INLINE
ulint
dtype_collate(
/*==========*/
/* out: collation order position */
dtype_t* type, /* in: type */
ulint code) /* in: character code stored in database
record */
{
ut_ad((type->mtype == DATA_CHAR) || (type->mtype == DATA_VARCHAR));
return(toupper(code));
}
/************************************************************************** /**************************************************************************
Stores to a type the information which determines its alphabetical Stores to a type the information which determines its alphabetical
ordering. */ ordering. */
...@@ -198,6 +181,10 @@ dtype_get_fixed_size( ...@@ -198,6 +181,10 @@ dtype_get_fixed_size(
case DATA_SYS: if (type->prtype == DATA_ROW_ID) { case DATA_SYS: if (type->prtype == DATA_ROW_ID) {
return(DATA_ROW_ID_LEN); return(DATA_ROW_ID_LEN);
} else if (type->prtype == DATA_TRX_ID) {
return(DATA_TRX_ID_LEN);
} else if (type->prtype == DATA_ROLL_PTR) {
return(DATA_ROLL_PTR_LEN);
} else { } else {
return(0); return(0);
} }
......
...@@ -27,11 +27,20 @@ Created 5/24/1996 Heikki Tuuri ...@@ -27,11 +27,20 @@ Created 5/24/1996 Heikki Tuuri
#define DB_CLUSTER_NOT_FOUND 30 #define DB_CLUSTER_NOT_FOUND 30
#define DB_TABLE_NOT_FOUND 31 #define DB_TABLE_NOT_FOUND 31
#define DB_MUST_GET_MORE_FILE_SPACE 32 /* the database has to be stopped #define DB_MUST_GET_MORE_FILE_SPACE 32 /* the database has to be stopped
and restrated with more file space */ and restarted with more file space */
#define DB_TABLE_IS_BEING_USED 33 #define DB_TABLE_IS_BEING_USED 33
#define DB_TOO_BIG_RECORD 34 /* a record in an index would become #define DB_TOO_BIG_RECORD 34 /* a record in an index would become
bigger than 1/2 free space in a page bigger than 1/2 free space in a page
frame */ frame */
#define DB_LOCK_WAIT_TIMEOUT 35 /* lock wait lasted too long */
#define DB_NO_REFERENCED_ROW 36 /* referenced key value not found
for a foreign key in an insert or
update of a row */
#define DB_ROW_IS_REFERENCED 37 /* cannot delete or update a row
because it contains a key value
which is referenced */
#define DB_CANNOT_ADD_CONSTRAINT 38 /* adding a foreign key constraint
to a table failed */
/* The following are partial failure codes */ /* The following are partial failure codes */
#define DB_FAIL 1000 #define DB_FAIL 1000
......
...@@ -71,6 +71,24 @@ dict_drop_index_tree( ...@@ -71,6 +71,24 @@ dict_drop_index_tree(
rec_t* rec, /* in: record in the clustered index of SYS_INDEXES rec_t* rec, /* in: record in the clustered index of SYS_INDEXES
table */ table */
mtr_t* mtr); /* in: mtr having the latch on the record page */ mtr_t* mtr); /* in: mtr having the latch on the record page */
/********************************************************************
Creates the foreign key constraints system tables inside InnoDB
at database creation or database start if they are not found or are
not of the right form. */
ulint
dict_create_or_check_foreign_constraint_tables(void);
/*================================================*/
/* out: DB_SUCCESS or error code */
/************************************************************************
Adds foreign key definitions to data dictionary tables in the database. */
ulint
dict_create_add_foreigns_to_dictionary(
/*===================================*/
/* out: error code or DB_SUCCESS */
dict_table_t* table, /* in: table */
trx_t* trx); /* in: transaction */
/* Table create node structure */ /* Table create node structure */
......
...@@ -138,6 +138,38 @@ dict_table_rename_in_cache( ...@@ -138,6 +138,38 @@ dict_table_rename_in_cache(
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
char* new_name); /* in: new name */ char* new_name); /* in: new name */
/************************************************************************** /**************************************************************************
Adds a foreign key constraint object to the dictionary cache. May free
the object if there already is an object with the same identifier in.
At least one of foreign table or referenced table must already be in
the dictionary cache! */
ulint
dict_foreign_add_to_cache(
/*======================*/
/* out: DB_SUCCESS or error code */
dict_foreign_t* foreign); /* in, own: foreign key constraint */
/*************************************************************************
Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function
should be called after the indexes for a table have been created.
Each foreign key constraint must be accompanied with indexes in
bot participating tables. The indexes are allowed to contain more
fields than mentioned in the constraint. */
ulint
dict_create_foreign_constraints(
/*============================*/
/* out: error code or DB_SUCCESS */
trx_t* trx, /* in: transaction */
char* sql_string, /* in: table create statement where
foreign keys are declared like:
FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the database
name before it: test.table2; the default
database id the database of parameter name */
char* name); /* in: table full name in the normalized form
database_name/table_name */
/**************************************************************************
Returns a table object and memoryfixes it. NOTE! This is a high-level Returns a table object and memoryfixes it. NOTE! This is a high-level
function to be used mainly from outside the 'dict' directory. Inside this function to be used mainly from outside the 'dict' directory. Inside this
directory dict_table_get_low is usually the appropriate function. */ directory dict_table_get_low is usually the appropriate function. */
...@@ -174,6 +206,14 @@ dict_table_release( ...@@ -174,6 +206,14 @@ dict_table_release(
/*===============*/ /*===============*/
dict_table_t* table); /* in: table to be released */ dict_table_t* table); /* in: table to be released */
/************************************************************************** /**************************************************************************
Checks if a table is in the dictionary cache. */
UNIV_INLINE
dict_table_t*
dict_table_check_if_in_cache_low(
/*==============================*/
/* out: table, NULL if not found */
char* table_name); /* in: table name */
/**************************************************************************
Gets a table; loads it to the dictionary cache if necessary. A low-level Gets a table; loads it to the dictionary cache if necessary. A low-level
function. */ function. */
UNIV_INLINE UNIV_INLINE
...@@ -208,6 +248,13 @@ dict_table_print( ...@@ -208,6 +248,13 @@ dict_table_print(
/*=============*/ /*=============*/
dict_table_t* table); /* in: table */ dict_table_t* table); /* in: table */
/************************************************************************** /**************************************************************************
Prints a table data. */
void
dict_table_print_low(
/*=================*/
dict_table_t* table); /* in: table */
/**************************************************************************
Prints a table data when we know the table name. */ Prints a table data when we know the table name. */
void void
...@@ -319,6 +366,16 @@ dict_table_copy_types( ...@@ -319,6 +366,16 @@ dict_table_copy_types(
dtuple_t* tuple, /* in: data tuple */ dtuple_t* tuple, /* in: data tuple */
dict_table_t* table); /* in: index */ dict_table_t* table); /* in: index */
/************************************************************************** /**************************************************************************
Looks for an index with the given id. NOTE that we do not reserve
the dictionary mutex: this function is for emergency purposes like
printing info of a corrupt database page! */
dict_index_t*
dict_index_find_on_id_low(
/*======================*/
/* out: index or NULL if not found from cache */
dulint id); /* in: index id */
/**************************************************************************
Adds an index to dictionary cache. */ Adds an index to dictionary cache. */
ibool ibool
...@@ -640,6 +697,23 @@ dict_tree_get_space_reserve( ...@@ -640,6 +697,23 @@ dict_tree_get_space_reserve(
reserved for updates */ reserved for updates */
dict_tree_t* tree); /* in: a tree */ dict_tree_t* tree); /* in: a tree */
/************************************************************************* /*************************************************************************
Calculates the minimum record length in an index. */
ulint
dict_index_calc_min_rec_len(
/*========================*/
dict_index_t* index); /* in: index */
/*************************************************************************
Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */
void
dict_update_statistics_low(
/*=======================*/
dict_table_t* table, /* in: table */
ibool has_dict_mutex);/* in: TRUE if the caller has the
dictionary mutex */
/*************************************************************************
Calculates new estimates for table and index statistics. The statistics Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */ are used in query optimization. */
...@@ -662,6 +736,7 @@ dict_mutex_exit_for_mysql(void); ...@@ -662,6 +736,7 @@ dict_mutex_exit_for_mysql(void);
extern dict_sys_t* dict_sys; /* the dictionary system */ extern dict_sys_t* dict_sys; /* the dictionary system */
extern rw_lock_t dict_foreign_key_check_lock;
/* Dictionary system struct */ /* Dictionary system struct */
struct dict_sys_struct{ struct dict_sys_struct{
......
...@@ -532,12 +532,11 @@ dict_tree_get_space_reserve( ...@@ -532,12 +532,11 @@ dict_tree_get_space_reserve(
} }
/************************************************************************** /**************************************************************************
Gets a table; loads it to the dictionary cache if necessary. A low-level Checks if a table is in the dictionary cache. */
function. */
UNIV_INLINE UNIV_INLINE
dict_table_t* dict_table_t*
dict_table_get_low( dict_table_check_if_in_cache_low(
/*===============*/ /*==============================*/
/* out: table, NULL if not found */ /* out: table, NULL if not found */
char* table_name) /* in: table name */ char* table_name) /* in: table name */
{ {
...@@ -552,6 +551,26 @@ dict_table_get_low( ...@@ -552,6 +551,26 @@ dict_table_get_low(
HASH_SEARCH(name_hash, dict_sys->table_hash, table_fold, table, HASH_SEARCH(name_hash, dict_sys->table_hash, table_fold, table,
ut_strcmp(table->name, table_name) == 0); ut_strcmp(table->name, table_name) == 0);
return(table);
}
/**************************************************************************
Gets a table; loads it to the dictionary cache if necessary. A low-level
function. */
UNIV_INLINE
dict_table_t*
dict_table_get_low(
/*===============*/
/* out: table, NULL if not found */
char* table_name) /* in: table name */
{
dict_table_t* table;
ut_ad(table_name);
ut_ad(mutex_own(&(dict_sys->mutex)));
table = dict_table_check_if_in_cache_low(table_name);
if (table == NULL) { if (table == NULL) {
table = dict_load_table(table_name); table = dict_load_table(table_name);
} }
...@@ -603,6 +622,7 @@ dict_table_get_on_id_low( ...@@ -603,6 +622,7 @@ dict_table_get_on_id_low(
dict_table_t* table; dict_table_t* table;
ulint fold; ulint fold;
ut_ad(mutex_own(&(dict_sys->mutex)));
UT_NOT_USED(trx); UT_NOT_USED(trx);
/* Look for the table name in the hash table */ /* Look for the table name in the hash table */
......
...@@ -14,9 +14,20 @@ Created 4/24/1996 Heikki Tuuri ...@@ -14,9 +14,20 @@ Created 4/24/1996 Heikki Tuuri
#include "dict0types.h" #include "dict0types.h"
#include "ut0byte.h" #include "ut0byte.h"
/************************************************************************
Finds the first table name in the given database. */
char*
dict_get_first_table_name_in_db(
/*============================*/
/* out, own: table name, NULL if does not exist;
the caller must free the memory in the string! */
char* name); /* in: database name which ends to '/' */
/************************************************************************ /************************************************************************
Loads a table definition and also all its index definitions, and also Loads a table definition and also all its index definitions, and also
the cluster definition, if the table is a member in a cluster. */ the cluster definition if the table is a member in a cluster. Also loads
all foreign key constraints where the foreign key is in the table or where
a foreign key references columns in this table. */
dict_table_t* dict_table_t*
dict_load_table( dict_load_table(
...@@ -40,6 +51,25 @@ void ...@@ -40,6 +51,25 @@ void
dict_load_sys_table( dict_load_sys_table(
/*================*/ /*================*/
dict_table_t* table); /* in: system table */ dict_table_t* table); /* in: system table */
/***************************************************************************
Loads foreign key constraints where the table is either the foreign key
holder or where the table is referenced by a foreign key. Adds these
constraints to the data dictionary. Note that we know that the dictionary
cache already contains all constraints where the other relevant table is
already in the dictionary cache. */
ulint
dict_load_foreigns(
/*===============*/
/* out: DB_SUCCESS or error code */
char* table_name); /* in: table name */
/************************************************************************
Prints to the standard output information on all tables found in the data
dictionary system table. */
void
dict_print(void);
/*============*/
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
......
...@@ -123,6 +123,13 @@ dict_mem_index_free( ...@@ -123,6 +123,13 @@ dict_mem_index_free(
/*================*/ /*================*/
dict_index_t* index); /* in: index */ dict_index_t* index); /* in: index */
/************************************************************************** /**************************************************************************
Creates and initializes a foreign constraint memory object. */
dict_foreign_t*
dict_mem_foreign_create(void);
/*=========================*/
/* out, own: foreign constraint struct */
/**************************************************************************
Creates a procedure memory object. */ Creates a procedure memory object. */
dict_proc_t* dict_proc_t*
...@@ -221,15 +228,56 @@ struct dict_index_struct{ ...@@ -221,15 +228,56 @@ struct dict_index_struct{
dictionary cache */ dictionary cache */
btr_search_t* search_info; /* info used in optimistic searches */ btr_search_t* search_info; /* info used in optimistic searches */
/*----------------------*/ /*----------------------*/
ulint stat_n_diff_key_vals; ib_longlong* stat_n_diff_key_vals;
/* approximate number of different key values /* approximate number of different key values
for this index; we periodically calculate for this index, for each n-column prefix
new estimates */ where n <= dict_get_n_unique(index); we
periodically calculate new estimates */
ulint stat_index_size; ulint stat_index_size;
/* approximate index size in database pages */ /* approximate index size in database pages */
ulint stat_n_leaf_pages;
/* approximate number of leaf pages in the
index tree */
ulint magic_n;/* magic number */ ulint magic_n;/* magic number */
}; };
/* Data structure for a foreign key constraint; an example:
FOREIGN KEY (A, B) REFERENCES TABLE2 (C, D) */
struct dict_foreign_struct{
mem_heap_t* heap; /* this object is allocated from
this memory heap */
char* id; /* id of the constraint as a
null-terminated string */
char* foreign_table_name;/* foreign table name */
dict_table_t* foreign_table; /* table where the foreign key is */
char** foreign_col_names;/* names of the columns in the
foreign key */
char* referenced_table_name;/* referenced table name */
dict_table_t* referenced_table;/* table where the referenced key
is */
char** referenced_col_names;/* names of the referenced
columns in the referenced table */
ulint n_fields; /* number of indexes' first fields
for which the the foreign key
constraint is defined: we allow the
indexes to contain more fields than
mentioned in the constraint, as long
as the first fields are as mentioned */
dict_index_t* foreign_index; /* foreign index; we require that
both tables contain explicitly defined
indexes for the constraint: InnoDB
does not generate new indexes
implicitly */
dict_index_t* referenced_index;/* referenced index */
UT_LIST_NODE_T(dict_foreign_t)
foreign_list; /* list node for foreign keys of the
table */
UT_LIST_NODE_T(dict_foreign_t)
referenced_list;/* list node for referenced keys of the
table */
};
#define DICT_INDEX_MAGIC_N 76789786 #define DICT_INDEX_MAGIC_N 76789786
/* Data structure for a database table */ /* Data structure for a database table */
...@@ -247,6 +295,13 @@ struct dict_table_struct{ ...@@ -247,6 +295,13 @@ struct dict_table_struct{
dict_col_t* cols; /* array of column descriptions */ dict_col_t* cols; /* array of column descriptions */
UT_LIST_BASE_NODE_T(dict_index_t) UT_LIST_BASE_NODE_T(dict_index_t)
indexes; /* list of indexes of the table */ indexes; /* list of indexes of the table */
UT_LIST_BASE_NODE_T(dict_foreign_t)
foreign_list;/* list of foreign key constraints
in the table; these refer to columns
in other tables */
UT_LIST_BASE_NODE_T(dict_foreign_t)
referenced_list;/* list of foreign key constraints
which refer to this table */
UT_LIST_NODE_T(dict_table_t) UT_LIST_NODE_T(dict_table_t)
table_LRU; /* node of the LRU list of tables */ table_LRU; /* node of the LRU list of tables */
ulint mem_fix;/* count of how many times the table ulint mem_fix;/* count of how many times the table
...@@ -254,6 +309,13 @@ struct dict_table_struct{ ...@@ -254,6 +309,13 @@ struct dict_table_struct{
currently NOT used */ currently NOT used */
ibool cached; /* TRUE if the table object has been added ibool cached; /* TRUE if the table object has been added
to the dictionary cache */ to the dictionary cache */
lock_t* auto_inc_lock;/* a buffer for an auto-inc lock
for this table: we allocate the memory here
so that individual transactions can get it
and release it without a need to allocate
space from the lock heap of the trx:
otherwise the lock heap would grow rapidly
if we do a large insert from a select */
UT_LIST_BASE_NODE_T(lock_t) UT_LIST_BASE_NODE_T(lock_t)
locks; /* list of locks on the table */ locks; /* list of locks on the table */
/*----------------------*/ /*----------------------*/
...@@ -278,7 +340,7 @@ struct dict_table_struct{ ...@@ -278,7 +340,7 @@ struct dict_table_struct{
forget about value TRUE if it has to reload forget about value TRUE if it has to reload
the table definition from disk */ the table definition from disk */
/*----------------------*/ /*----------------------*/
ulint stat_n_rows; ib_longlong stat_n_rows;
/* approximate number of rows in the table; /* approximate number of rows in the table;
we periodically calculate new estimates */ we periodically calculate new estimates */
ulint stat_clustered_index_size; ulint stat_clustered_index_size;
......
...@@ -16,6 +16,7 @@ typedef struct dict_index_struct dict_index_t; ...@@ -16,6 +16,7 @@ typedef struct dict_index_struct dict_index_t;
typedef struct dict_tree_struct dict_tree_t; typedef struct dict_tree_struct dict_tree_t;
typedef struct dict_table_struct dict_table_t; typedef struct dict_table_struct dict_table_t;
typedef struct dict_proc_struct dict_proc_t; typedef struct dict_proc_struct dict_proc_t;
typedef struct dict_foreign_struct dict_foreign_t;
/* A cluster object is a table object with the type field set to /* A cluster object is a table object with the type field set to
DICT_CLUSTERED */ DICT_CLUSTERED */
......
...@@ -76,6 +76,9 @@ extern fil_addr_t fil_addr_null; ...@@ -76,6 +76,9 @@ extern fil_addr_t fil_addr_null;
#define FIL_TABLESPACE 501 #define FIL_TABLESPACE 501
#define FIL_LOG 502 #define FIL_LOG 502
extern ulint fil_n_pending_log_flushes;
extern ulint fil_n_pending_tablespace_flushes;
/*********************************************************************** /***********************************************************************
Reserves a right to open a single file. The right must be released with Reserves a right to open a single file. The right must be released with
fil_release_right_to_open. */ fil_release_right_to_open. */
......
...@@ -226,6 +226,21 @@ ibuf_contract( ...@@ -226,6 +226,21 @@ ibuf_contract(
issued read with the highest tablespace address issued read with the highest tablespace address
to complete */ to complete */
/************************************************************************* /*************************************************************************
Contracts insert buffer trees by reading pages to the buffer pool. */
ulint
ibuf_contract_for_n_pages(
/*======================*/
/* out: a lower limit for the combined size in bytes
of entries which will be merged from ibuf trees to the
pages read, 0 if ibuf is empty */
ibool sync, /* in: TRUE if the caller wants to wait for the
issued read with the highest tablespace address
to complete */
ulint n_pages);/* in: try to read at least this many pages to
the buffer pool and merge the ibuf contents to
them */
/*************************************************************************
Parses a redo log record of an ibuf bitmap page init. */ Parses a redo log record of an ibuf bitmap page init. */
byte* byte*
......
...@@ -21,15 +21,13 @@ Created 5/7/1996 Heikki Tuuri ...@@ -21,15 +21,13 @@ Created 5/7/1996 Heikki Tuuri
extern ibool lock_print_waits; extern ibool lock_print_waits;
/***************************************************************** /*************************************************************************
Cancels a waiting record lock request and releases the waiting transaction Gets the size of a lock struct. */
that requested it. NOTE: does NOT check if waiting lock requests behind this
one can now be granted! */
void ulint
lock_rec_cancel( lock_get_size(void);
/*============*/ /*===============*/
lock_t* lock); /* in: waiting record lock request */ /* out: size in bytes */
/************************************************************************* /*************************************************************************
Creates the lock system at database start. */ Creates the lock system at database start. */
...@@ -388,6 +386,14 @@ lock_is_on_table( ...@@ -388,6 +386,14 @@ lock_is_on_table(
/* out: TRUE if there are lock(s) */ /* out: TRUE if there are lock(s) */
dict_table_t* table); /* in: database table in dictionary cache */ dict_table_t* table); /* in: database table in dictionary cache */
/************************************************************************* /*************************************************************************
Releases an auto-inc lock a transaction possibly has on a table.
Releases possible other transactions waiting for this lock. */
void
lock_table_unlock_auto_inc(
/*=======================*/
trx_t* trx); /* in: transaction */
/*************************************************************************
Releases transaction locks, and releases possible other transactions waiting Releases transaction locks, and releases possible other transactions waiting
because of these locks. */ because of these locks. */
...@@ -396,6 +402,14 @@ lock_release_off_kernel( ...@@ -396,6 +402,14 @@ lock_release_off_kernel(
/*====================*/ /*====================*/
trx_t* trx); /* in: transaction */ trx_t* trx); /* in: transaction */
/************************************************************************* /*************************************************************************
Cancels a waiting lock request and releases possible other transactions
waiting behind it. */
void
lock_cancel_waiting_and_release(
/*============================*/
lock_t* lock); /* in: waiting lock request */
/*************************************************************************
Resets all locks, both table and record locks, on a table to be dropped. Resets all locks, both table and record locks, on a table to be dropped.
No lock is allowed to be a wait lock. */ No lock is allowed to be a wait lock. */
...@@ -495,6 +509,8 @@ extern lock_sys_t* lock_sys; ...@@ -495,6 +509,8 @@ extern lock_sys_t* lock_sys;
#define LOCK_IX 3 /* intention exclusive */ #define LOCK_IX 3 /* intention exclusive */
#define LOCK_S 4 /* shared */ #define LOCK_S 4 /* shared */
#define LOCK_X 5 /* exclusive */ #define LOCK_X 5 /* exclusive */
#define LOCK_AUTO_INC 6 /* locks the auto-inc counter of a table
in an exclusive mode */
#define LOCK_MODE_MASK 0xF /* mask used to extract mode from the #define LOCK_MODE_MASK 0xF /* mask used to extract mode from the
type_mode field in a lock */ type_mode field in a lock */
#define LOCK_TABLE 16 /* these type values should be so high that */ #define LOCK_TABLE 16 /* these type values should be so high that */
......
...@@ -659,6 +659,11 @@ struct log_struct{ ...@@ -659,6 +659,11 @@ struct log_struct{
mutex! */ mutex! */
ulint n_log_ios; /* number of log i/os initiated thus ulint n_log_ios; /* number of log i/os initiated thus
far */ far */
ulint n_log_ios_old; /* number of log i/o's at the
previous printout */
time_t last_printout_time;/* when log_print was last time
called */
/* Fields involved in checkpoints */ /* Fields involved in checkpoints */
ulint max_modified_age_async; ulint max_modified_age_async;
/* when this recommended value for lsn /* when this recommended value for lsn
......
...@@ -203,20 +203,12 @@ mtr_read_dulint( ...@@ -203,20 +203,12 @@ mtr_read_dulint(
mtr_t* mtr); /* in: mini-transaction handle */ mtr_t* mtr); /* in: mini-transaction handle */
/************************************************************************* /*************************************************************************
This macro locks an rw-lock in s-mode. */ This macro locks an rw-lock in s-mode. */
#ifdef UNIV_SYNC_DEBUG
#define mtr_s_lock(B, MTR) mtr_s_lock_func((B), IB__FILE__, __LINE__,\ #define mtr_s_lock(B, MTR) mtr_s_lock_func((B), IB__FILE__, __LINE__,\
(MTR)) (MTR))
#else
#define mtr_s_lock(B, MTR) mtr_s_lock_func((B), (MTR))
#endif
/************************************************************************* /*************************************************************************
This macro locks an rw-lock in x-mode. */ This macro locks an rw-lock in x-mode. */
#ifdef UNIV_SYNC_DEBUG
#define mtr_x_lock(B, MTR) mtr_x_lock_func((B), IB__FILE__, __LINE__,\ #define mtr_x_lock(B, MTR) mtr_x_lock_func((B), IB__FILE__, __LINE__,\
(MTR)) (MTR))
#else
#define mtr_x_lock(B, MTR) mtr_x_lock_func((B), (MTR))
#endif
/************************************************************************* /*************************************************************************
NOTE! Use the macro above! NOTE! Use the macro above!
Locks a lock in s-mode. */ Locks a lock in s-mode. */
...@@ -225,10 +217,8 @@ void ...@@ -225,10 +217,8 @@ void
mtr_s_lock_func( mtr_s_lock_func(
/*============*/ /*============*/
rw_lock_t* lock, /* in: rw-lock */ rw_lock_t* lock, /* in: rw-lock */
#ifdef UNIV_SYNC_DEBUG
char* file, /* in: file name */ char* file, /* in: file name */
ulint line, /* in: line number */ ulint line, /* in: line number */
#endif
mtr_t* mtr); /* in: mtr */ mtr_t* mtr); /* in: mtr */
/************************************************************************* /*************************************************************************
NOTE! Use the macro above! NOTE! Use the macro above!
...@@ -238,10 +228,8 @@ void ...@@ -238,10 +228,8 @@ void
mtr_x_lock_func( mtr_x_lock_func(
/*============*/ /*============*/
rw_lock_t* lock, /* in: rw-lock */ rw_lock_t* lock, /* in: rw-lock */
#ifdef UNIV_SYNC_DEBUG
char* file, /* in: file name */ char* file, /* in: file name */
ulint line, /* in: line number */ ulint line, /* in: line number */
#endif
mtr_t* mtr); /* in: mtr */ mtr_t* mtr); /* in: mtr */
/******************************************************* /*******************************************************
......
...@@ -217,20 +217,14 @@ void ...@@ -217,20 +217,14 @@ void
mtr_s_lock_func( mtr_s_lock_func(
/*============*/ /*============*/
rw_lock_t* lock, /* in: rw-lock */ rw_lock_t* lock, /* in: rw-lock */
#ifdef UNIV_SYNC_DEBUG
char* file, /* in: file name */ char* file, /* in: file name */
ulint line, /* in: line number */ ulint line, /* in: line number */
#endif
mtr_t* mtr) /* in: mtr */ mtr_t* mtr) /* in: mtr */
{ {
ut_ad(mtr); ut_ad(mtr);
ut_ad(lock); ut_ad(lock);
rw_lock_s_lock_func(lock rw_lock_s_lock_func(lock, 0, file, line);
#ifdef UNIV_SYNC_DEBUG
,0, file, line
#endif
);
mtr_memo_push(mtr, lock, MTR_MEMO_S_LOCK); mtr_memo_push(mtr, lock, MTR_MEMO_S_LOCK);
} }
...@@ -242,20 +236,14 @@ void ...@@ -242,20 +236,14 @@ void
mtr_x_lock_func( mtr_x_lock_func(
/*============*/ /*============*/
rw_lock_t* lock, /* in: rw-lock */ rw_lock_t* lock, /* in: rw-lock */
#ifdef UNIV_SYNC_DEBUG
char* file, /* in: file name */ char* file, /* in: file name */
ulint line, /* in: line number */ ulint line, /* in: line number */
#endif
mtr_t* mtr) /* in: mtr */ mtr_t* mtr) /* in: mtr */
{ {
ut_ad(mtr); ut_ad(mtr);
ut_ad(lock); ut_ad(lock);
rw_lock_x_lock_func(lock, 0 rw_lock_x_lock_func(lock, 0, file, line);
#ifdef UNIV_SYNC_DEBUG
, file, line
#endif
);
mtr_memo_push(mtr, lock, MTR_MEMO_X_LOCK); mtr_memo_push(mtr, lock, MTR_MEMO_X_LOCK);
} }
...@@ -15,6 +15,32 @@ Created 7/1/1994 Heikki Tuuri ...@@ -15,6 +15,32 @@ Created 7/1/1994 Heikki Tuuri
#include "dict0dict.h" #include "dict0dict.h"
#include "rem0rec.h" #include "rem0rec.h"
/*****************************************************************
Returns TRUE if two types are equal for comparison purposes. */
ibool
cmp_types_are_equal(
/*================*/
/* out: TRUE if the types are considered
equal in comparisons */
dtype_t* type1, /* in: type 1 */
dtype_t* type2); /* in: type 2 */
/*****************************************************************
This function is used to compare two data fields for which we know the
data type. */
UNIV_INLINE
int
cmp_data_data(
/*==========*/
/* out: 1, 0, -1, if data1 is greater, equal,
less than data2, respectively */
dtype_t* cur_type,/* in: data type of the fields */
byte* data1, /* in: data field (== a pointer to a memory
buffer) */
ulint len1, /* in: data field length or UNIV_SQL_NULL */
byte* data2, /* in: data field (== a pointer to a memory
buffer) */
ulint len2); /* in: data field length or UNIV_SQL_NULL */
/***************************************************************** /*****************************************************************
This function is used to compare two dfields where at least the first This function is used to compare two dfields where at least the first
has its data type field set. */ has its data type field set. */
......
...@@ -16,6 +16,28 @@ Created 4/20/1996 Heikki Tuuri ...@@ -16,6 +16,28 @@ Created 4/20/1996 Heikki Tuuri
#include "trx0types.h" #include "trx0types.h"
#include "row0types.h" #include "row0types.h"
/*******************************************************************
Checks if foreign key constraint fails for an index entry. Sets shared locks
which lock either the success or the failure of the constraint. NOTE that
the caller must have a shared latch on dict_foreign_key_check_lock. */
ulint
row_ins_check_foreign_constraint(
/*=============================*/
/* out: DB_SUCCESS, DB_LOCK_WAIT,
DB_NO_REFERENCED_ROW,
or DB_ROW_IS_REFERENCED */
ibool check_ref,/* in: TRUE If we want to check that
the referenced table is ok, FALSE if we
want to to check the foreign key table */
dict_foreign_t* foreign,/* in: foreign constraint; NOTE that the
tables mentioned in it must be in the
dictionary cache if they exist at all */
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
table, else the referenced table */
dict_index_t* index, /* in: index in table */
dtuple_t* entry, /* in: index entry for index */
que_thr_t* thr); /* in: query thread */
/************************************************************************* /*************************************************************************
Creates an insert node struct. */ Creates an insert node struct. */
......
...@@ -133,6 +133,26 @@ row_update_prebuilt_trx( ...@@ -133,6 +133,26 @@ row_update_prebuilt_trx(
handle */ handle */
trx_t* trx); /* in: transaction handle */ trx_t* trx); /* in: transaction handle */
/************************************************************************* /*************************************************************************
Unlocks an AUTO_INC type lock possibly reserved by trx. */
void
row_unlock_table_autoinc_for_mysql(
/*===============================*/
trx_t* trx); /* in: transaction */
/*************************************************************************
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
AUTO_INC lock gives exclusive access to the auto-inc counter of the
table. The lock is reserved only for the duration of an SQL statement.
It is not compatible with another AUTO_INC or exclusive lock on the
table. */
int
row_lock_table_autoinc_for_mysql(
/*=============================*/
/* out: error code or DB_SUCCESS */
row_prebuilt_t* prebuilt); /* in: prebuilt struct in the MySQL
table handle */
/*************************************************************************
Does an insert for MySQL. */ Does an insert for MySQL. */
int int
...@@ -211,6 +231,26 @@ row_create_index_for_mysql( ...@@ -211,6 +231,26 @@ row_create_index_for_mysql(
dict_index_t* index, /* in: index defintion */ dict_index_t* index, /* in: index defintion */
trx_t* trx); /* in: transaction handle */ trx_t* trx); /* in: transaction handle */
/************************************************************************* /*************************************************************************
Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function
should be called after the indexes for a table have been created.
Each foreign key constraint must be accompanied with indexes in
bot participating tables. The indexes are allowed to contain more
fields than mentioned in the constraint. */
int
row_table_add_foreign_constraints(
/*==============================*/
/* out: error code or DB_SUCCESS */
trx_t* trx, /* in: transaction */
char* sql_string, /* in: table create statement where
foreign keys are declared like:
FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the database
name before it: test.table2 */
char* name); /* in: table full name in the normalized form
database_name/table_name */
/*************************************************************************
Drops a table for MySQL. If the name of the dropped table ends to Drops a table for MySQL. If the name of the dropped table ends to
characters INNODB_MONITOR, then this also stops printing of monitor characters INNODB_MONITOR, then this also stops printing of monitor
output by the master thread. */ output by the master thread. */
...@@ -224,6 +264,15 @@ row_drop_table_for_mysql( ...@@ -224,6 +264,15 @@ row_drop_table_for_mysql(
ibool has_dict_mutex);/* in: TRUE if the caller already owns the ibool has_dict_mutex);/* in: TRUE if the caller already owns the
dictionary system mutex */ dictionary system mutex */
/************************************************************************* /*************************************************************************
Drops a database for MySQL. */
int
row_drop_database_for_mysql(
/*========================*/
/* out: error code or DB_SUCCESS */
char* name, /* in: database name which ends to '/' */
trx_t* trx); /* in: transaction handle */
/*************************************************************************
Renames a table for MySQL. */ Renames a table for MySQL. */
int int
......
...@@ -47,8 +47,7 @@ upd_get_nth_field( ...@@ -47,8 +47,7 @@ upd_get_nth_field(
upd_t* update, /* in: update vector */ upd_t* update, /* in: update vector */
ulint n); /* in: field position in update vector */ ulint n); /* in: field position in update vector */
/************************************************************************* /*************************************************************************
Sets the clustered index field number to be updated by an update vector Sets an index field number to be updated by an update vector field. */
field. */
UNIV_INLINE UNIV_INLINE
void void
upd_field_set_field_no( upd_field_set_field_no(
...@@ -56,7 +55,7 @@ upd_field_set_field_no( ...@@ -56,7 +55,7 @@ upd_field_set_field_no(
upd_field_t* upd_field, /* in: update vector field */ upd_field_t* upd_field, /* in: update vector field */
ulint field_no, /* in: field number in a clustered ulint field_no, /* in: field number in a clustered
index */ index */
dict_index_t* index); /* in: clustered index */ dict_index_t* index); /* in: index */
/************************************************************************* /*************************************************************************
Writes into the redo log the values of trx id and roll ptr and enough info Writes into the redo log the values of trx id and roll ptr and enough info
to determine their positions within a clustered index record. */ to determine their positions within a clustered index record. */
...@@ -136,13 +135,27 @@ row_upd_rec_in_place( ...@@ -136,13 +135,27 @@ row_upd_rec_in_place(
rec_t* rec, /* in/out: record where replaced */ rec_t* rec, /* in/out: record where replaced */
upd_t* update);/* in: update vector */ upd_t* update);/* in: update vector */
/******************************************************************* /*******************************************************************
Builds an update vector from those fields which in a secondary index entry
differ from a record that has the equal ordering fields. NOTE: we compare
the fields as binary strings! */
upd_t*
row_upd_build_sec_rec_difference_binary(
/*====================================*/
/* out, own: update vector of differing
fields */
dict_index_t* index, /* in: index */
dtuple_t* entry, /* in: entry to insert */
rec_t* rec, /* in: secondary index record */
mem_heap_t* heap); /* in: memory heap from which allocated */
/*******************************************************************
Builds an update vector from those fields, excluding the roll ptr and Builds an update vector from those fields, excluding the roll ptr and
trx id fields, which in an index entry differ from a record that has trx id fields, which in an index entry differ from a record that has
the equal ordering fields. */ the equal ordering fields. NOTE: we compare the fields as binary strings! */
upd_t* upd_t*
row_upd_build_difference( row_upd_build_difference_binary(
/*=====================*/ /*============================*/
/* out, own: update vector of differing /* out, own: update vector of differing
fields, excluding roll ptr and trx id */ fields, excluding roll ptr and trx id */
dict_index_t* index, /* in: clustered index */ dict_index_t* index, /* in: clustered index */
...@@ -175,13 +188,16 @@ row_upd_clust_index_replace_new_col_vals( ...@@ -175,13 +188,16 @@ row_upd_clust_index_replace_new_col_vals(
/*************************************************************** /***************************************************************
Checks if an update vector changes an ordering field of an index record. Checks if an update vector changes an ordering field of an index record.
This function is fast if the update vector is short or the number of ordering This function is fast if the update vector is short or the number of ordering
fields in the index is small. Otherwise, this can be quadratic. */ fields in the index is small. Otherwise, this can be quadratic.
NOTE: we compare the fields as binary strings! */
ibool ibool
row_upd_changes_ord_field( row_upd_changes_ord_field_binary(
/*======================*/ /*=============================*/
/* out: TRUE if update vector changes /* out: TRUE if update vector changes
an ordering field in the index record */ an ordering field in the index record;
NOTE: the fields are compared as binary
strings */
dtuple_t* row, /* in: old value of row, or NULL if the dtuple_t* row, /* in: old value of row, or NULL if the
row and the data values in update are not row and the data values in update are not
known when this function is called, e.g., at known when this function is called, e.g., at
...@@ -191,11 +207,12 @@ row_upd_changes_ord_field( ...@@ -191,11 +207,12 @@ row_upd_changes_ord_field(
/*************************************************************** /***************************************************************
Checks if an update vector changes an ordering field of an index record. Checks if an update vector changes an ordering field of an index record.
This function is fast if the update vector is short or the number of ordering This function is fast if the update vector is short or the number of ordering
fields in the index is small. Otherwise, this can be quadratic. */ fields in the index is small. Otherwise, this can be quadratic.
NOTE: we compare the fields as binary strings! */
ibool ibool
row_upd_changes_some_index_ord_field( row_upd_changes_some_index_ord_field_binary(
/*=================================*/ /*========================================*/
/* out: TRUE if update vector may change /* out: TRUE if update vector may change
an ordering field in an index record */ an ordering field in an index record */
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
......
...@@ -70,8 +70,7 @@ upd_get_nth_field( ...@@ -70,8 +70,7 @@ upd_get_nth_field(
} }
/************************************************************************* /*************************************************************************
Sets the clustered index field number to be updated by an update vector Sets an index field number to be updated by an update vector field. */
field. */
UNIV_INLINE UNIV_INLINE
void void
upd_field_set_field_no( upd_field_set_field_no(
...@@ -79,12 +78,18 @@ upd_field_set_field_no( ...@@ -79,12 +78,18 @@ upd_field_set_field_no(
upd_field_t* upd_field, /* in: update vector field */ upd_field_t* upd_field, /* in: update vector field */
ulint field_no, /* in: field number in a clustered ulint field_no, /* in: field number in a clustered
index */ index */
dict_index_t* index) /* in: clustered index */ dict_index_t* index) /* in: index */
{ {
ut_ad(index->type & DICT_CLUSTERED);
upd_field->field_no = field_no; upd_field->field_no = field_no;
if (field_no >= dict_index_get_n_fields(index)) {
fprintf(stderr,
"InnoDB: Error: trying to access field %lu in table %s\n"
"InnoDB: index %s, but index has only %lu fields\n",
field_no, index->table_name, index->name,
dict_index_get_n_fields(index));
}
dtype_copy(dfield_get_type(&(upd_field->new_val)), dtype_copy(dfield_get_type(&(upd_field->new_val)),
dict_index_get_nth_type(index, field_no)); dict_index_get_nth_type(index, field_no));
} }
......
This diff is collapsed.
...@@ -51,12 +51,8 @@ sync_array_reserve_cell( ...@@ -51,12 +51,8 @@ sync_array_reserve_cell(
sync_array_t* arr, /* in: wait array */ sync_array_t* arr, /* in: wait array */
void* object, /* in: pointer to the object to wait for */ void* object, /* in: pointer to the object to wait for */
ulint type, /* in: lock request type */ ulint type, /* in: lock request type */
#ifdef UNIV_SYNC_DEBUG char* file, /* in: file where requested */
char* file, /* in: in debug version file where ulint line, /* in: line where requested */
requested */
ulint line, /* in: in the debug version line where
requested */
#endif
ulint* index); /* out: index of the reserved cell */ ulint* index); /* out: index of the reserved cell */
/********************************************************************** /**********************************************************************
This function should be called when a thread starts to wait on This function should be called when a thread starts to wait on
...@@ -90,6 +86,20 @@ sync_array_signal_object( ...@@ -90,6 +86,20 @@ sync_array_signal_object(
/*=====================*/ /*=====================*/
sync_array_t* arr, /* in: wait array */ sync_array_t* arr, /* in: wait array */
void* object);/* in: wait object */ void* object);/* in: wait object */
/**************************************************************************
If the wakeup algorithm does not work perfectly at semaphore relases,
this function will do the waking (see the comment in mutex_exit). This
function should be called about every 1 second in the server. */
void
sync_arr_wake_threads_if_sema_free(void);
/*====================================*/
/**************************************************************************
Prints warnings of long semaphore waits to stderr. Currently > 120 sec. */
void
sync_array_print_long_waits(void);
/*=============================*/
/************************************************************************ /************************************************************************
Validates the integrity of the wait array. Checks Validates the integrity of the wait array. Checks
that the number of reserved cells equals the count variable. */ that the number of reserved cells equals the count variable. */
......
...@@ -92,7 +92,7 @@ loop: ...@@ -92,7 +92,7 @@ loop:
loop_count++; loop_count++;
ut_ad(loop_count < 15); ut_ad(loop_count < 15);
if (mutex_enter_nowait(mutex) == 0) { if (mutex_enter_nowait(mutex, IB__FILE__, __LINE__) == 0) {
/* Succeeded! */ /* Succeeded! */
return(0); return(0);
...@@ -105,7 +105,7 @@ loop: ...@@ -105,7 +105,7 @@ loop:
/* Order is important here: FIRST reset event, then set waiters */ /* Order is important here: FIRST reset event, then set waiters */
ip_mutex_set_waiters(ip_mutex, 1); ip_mutex_set_waiters(ip_mutex, 1);
if (mutex_enter_nowait(mutex) == 0) { if (mutex_enter_nowait(mutex, IB__FILE__, __LINE__) == 0) {
/* Succeeded! */ /* Succeeded! */
return(0); return(0);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -61,7 +61,11 @@ trx_rsegf_get_nth_undo( ...@@ -61,7 +61,11 @@ trx_rsegf_get_nth_undo(
ulint n, /* in: index of slot */ ulint n, /* in: index of slot */
mtr_t* mtr) /* in: mtr */ mtr_t* mtr) /* in: mtr */
{ {
ut_ad(n < TRX_RSEG_N_SLOTS); if (n >= TRX_RSEG_N_SLOTS) {
fprintf(stderr,
"InnoDB: Error: trying to get slot %lu of rseg\n", n);
ut_a(0);
}
return(mtr_read_ulint(rsegf + TRX_RSEG_UNDO_SLOTS + return(mtr_read_ulint(rsegf + TRX_RSEG_UNDO_SLOTS +
n * TRX_RSEG_SLOT_SIZE, MLOG_4BYTES, mtr)); n * TRX_RSEG_SLOT_SIZE, MLOG_4BYTES, mtr));
...@@ -78,7 +82,11 @@ trx_rsegf_set_nth_undo( ...@@ -78,7 +82,11 @@ trx_rsegf_set_nth_undo(
ulint page_no,/* in: page number of the undo log segment */ ulint page_no,/* in: page number of the undo log segment */
mtr_t* mtr) /* in: mtr */ mtr_t* mtr) /* in: mtr */
{ {
ut_ad(n < TRX_RSEG_N_SLOTS); if (n >= TRX_RSEG_N_SLOTS) {
fprintf(stderr,
"InnoDB: Error: trying to set slot %lu of rseg\n", n);
ut_a(0);
}
mlog_write_ulint(rsegf + TRX_RSEG_UNDO_SLOTS + n * TRX_RSEG_SLOT_SIZE, mlog_write_ulint(rsegf + TRX_RSEG_UNDO_SLOTS + n * TRX_RSEG_SLOT_SIZE,
page_no, MLOG_4BYTES, mtr); page_no, MLOG_4BYTES, mtr);
......
This diff is collapsed.
...@@ -13,6 +13,9 @@ Created 5/30/1994 Heikki Tuuri ...@@ -13,6 +13,9 @@ Created 5/30/1994 Heikki Tuuri
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
/* The total amount of memory currently allocated from the OS with malloc */
extern ulint ut_total_allocated_memory;
UNIV_INLINE UNIV_INLINE
void* void*
ut_memcpy(void* dest, void* sour, ulint n); ut_memcpy(void* dest, void* sour, ulint n);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -1258,8 +1258,8 @@ page_validate( ...@@ -1258,8 +1258,8 @@ page_validate(
page_dir_get_nth_slot(page, n_slots - 1))) { page_dir_get_nth_slot(page, n_slots - 1))) {
fprintf(stderr, fprintf(stderr,
"Record heap and dir overlap on a page in index %s, %lu, %lu\n", "Record heap and dir overlap on a page in index %s, %lu, %lu\n",
index->name, page_header_get_ptr(page, PAGE_HEAP_TOP), index->name, (ulint)page_header_get_ptr(page, PAGE_HEAP_TOP),
page_dir_get_nth_slot(page, n_slots - 1)); (ulint)page_dir_get_nth_slot(page, n_slots - 1));
goto func_exit; goto func_exit;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
require_manager;
connect (master,localhost,root,,test,0,master.sock); connect (master,localhost,root,,test,0,master.sock);
connect (slave,localhost,root,,test,0,slave.sock); connect (slave,localhost,root,,test,0,slave.sock);
server_stop master; server_stop master;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment