Merge hynda.mysql.fi:/home/my/mysql-5.1-main

into  hynda.mysql.fi:/home/my/mysql-maria


BitKeeper/etc/ignore:
  auto-union
BUILD/SETUP.sh:
  Auto merged
BitKeeper/deleted/.del-CMakeLists.txt~99a50df6:
  Auto merged
Makefile.am:
  Auto merged
client/mysqldump.c:
  Auto merged
configure.in:
  Auto merged
include/Makefile.am:
  Auto merged
include/keycache.h:
  Auto merged
include/m_string.h:
  Auto merged
include/my_sys.h:
  Auto merged
libmysqld/Makefile.am:
  Auto merged
mysql-test/extra/rpl_tests/rpl_insert_delayed.test:
  Auto merged
mysql-test/lib/mtr_cases.pl:
  Auto merged
mysql-test/lib/mtr_misc.pl:
  Auto merged
mysql-test/lib/mtr_process.pl:
  Auto merged
mysql-test/lib/mtr_report.pl:
  Auto merged
mysql-test/lib/mtr_timer.pl:
  Auto merged
mysql-test/mysql-test-run.pl:
  Auto merged
mysql-test/r/alter_table.result:
  Auto merged
mysql-test/r/merge.result:
  Auto merged
mysql-test/r/mysqldump.result:
  Auto merged
mysql-test/r/query_cache.result:
  Auto merged
mysql-test/r/subselect.result:
  Auto merged
mysql-test/r/view.result:
  Auto merged
mysql-test/suite/ndb/r/ps_7ndb.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_events.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_insert.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_row_insert_delayed.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_stm_insert_delayed.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result:
  Auto merged
mysql-test/suite/rpl/t/rpl_insert.test:
  Auto merged
mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test:
  Auto merged
mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test:
  Auto merged
mysql-test/t/alter_table.test:
  Auto merged
mysql-test/t/myisam.test:
  Auto merged
mysql-test/t/mysqldump.test:
  Auto merged
mysql-test/t/query_cache.test:
  Auto merged
mysql-test/t/subselect.test:
  Auto merged
mysql-test/t/view.test:
  Auto merged
mysys/array.c:
  Auto merged
mysys/mf_keycache.c:
  Auto merged
mysys/my_init.c:
  Auto merged
mysys/my_symlink2.c:
  Auto merged
mysys/safemalloc.c:
  Auto merged
mysys/thr_lock.c:
  Auto merged
sql/Makefile.am:
  Auto merged
sql/filesort.cc:
  Auto merged
sql/ha_ndbcluster.cc:
  Auto merged
sql/ha_partition.cc:
  Auto merged
sql/ha_partition.h:
  Auto merged
sql/handler.h:
  Auto merged
sql/item_func.cc:
  Auto merged
sql/item_func.h:
  Auto merged
sql/item_xmlfunc.cc:
  Auto merged
sql/lock.cc:
  Auto merged
sql/log.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/net_serv.cc:
  Auto merged
sql/opt_range.cc:
  Auto merged
sql/set_var.cc:
  Auto merged
sql/slave.cc:
  Auto merged
sql/slave.h:
  Auto merged
sql/sql_class.cc:
  Auto merged
sql/sql_delete.cc:
  Auto merged
sql/sql_insert.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
sql/share/errmsg.txt:
  Auto merged
sql/sql_test.cc:
  Auto merged
sql/table.h:
  Auto merged
sql/udf_example.c:
  Auto merged
sql/uniques.cc:
  Auto merged
sql/unireg.cc:
  Auto merged
storage/csv/ha_tina.h:
  Auto merged
storage/myisam/ft_boolean_search.c:
  Auto merged
storage/myisam/ft_nlq_search.c:
  Auto merged
storage/myisam/ft_parser.c:
  Auto merged
storage/myisam/ft_stopwords.c:
  Auto merged
storage/myisam/ha_myisam.cc:
  Auto merged
storage/myisam/ha_myisam.h:
  Auto merged
storage/myisam/mi_check.c:
  Auto merged
storage/myisam/mi_create.c:
  Auto merged
storage/myisam/mi_delete.c:
  Auto merged
storage/myisam/mi_dynrec.c:
  Auto merged
storage/myisam/mi_extra.c:
  Auto merged
storage/myisam/mi_key.c:
  Auto merged
storage/myisam/mi_locking.c:
  Auto merged
storage/myisam/mi_log.c:
  Auto merged
storage/myisam/mi_packrec.c:
  Auto merged
storage/myisam/mi_rkey.c:
  Auto merged
storage/myisam/mi_search.c:
  Auto merged
storage/myisam/mi_test1.c:
  Auto merged
storage/myisam/mi_test2.c:
  Auto merged
storage/myisam/mi_update.c:
  Auto merged
storage/myisam/mi_write.c:
  Auto merged
storage/myisam/myisamchk.c:
  Auto merged
storage/myisam/myisamlog.c:
  Auto merged
storage/myisam/myisampack.c:
  Auto merged
storage/myisam/sort.c:
  Auto merged
storage/myisam/sp_test.c:
  Auto merged
storage/myisammrg/ha_myisammrg.cc:
  Auto merged
storage/myisammrg/ha_myisammrg.h:
  Auto merged
storage/ndb/src/mgmapi/mgmapi.cpp:
  Auto merged
support-files/compiler_warnings.supp:
  Auto merged
client/mysqltest.c:
  Manual merge between mysql-5.1 and mysql-maria
include/my_base.h:
  Manual merge between mysql-5.1 and mysql-maria
include/my_global.h:
  Manual merge between mysql-5.1 and mysql-maria
include/myisam.h:
  Manual merge between mysql-5.1 and mysql-maria
libmysql/Makefile.shared:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/r/events_logs_tests.result:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/t/disabled.def:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/t/events_logs_tests.test:
  Manual merge between mysql-5.1 and mysql-maria
mysys/my_compress.c:
  Manual merge between mysql-5.1 and mysql-maria
mysys/my_getsystime.c:
  Manual merge between mysql-5.1 and mysql-maria
mysys/my_open.c:
  Manual merge between mysql-5.1 and mysql-maria
sql/handler.cc:
  Manual merge between mysql-5.1 and mysql-maria
sql/set_var.h:
  Manual merge between mysql-5.1 and mysql-maria
sql/sql_class.h:
  Manual merge between mysql-5.1 and mysql-maria
sql/sql_show.cc:
  Manual merge between mysql-5.1 and mysql-maria
sql/sql_sort.h:
  Manual merge between mysql-5.1 and mysql-maria
sql/sql_yacc.yy:
  Manual merge between mysql-5.1 and mysql-maria
sql/table.cc:
  Manual merge between mysql-5.1 and mysql-maria
storage/csv/ha_tina.cc:
  Manual merge between mysql-5.1 and mysql-maria
storage/myisam/mi_open.c:
  Manual merge between mysql-5.1 and mysql-maria
storage/myisam/myisamdef.h:
  Manual merge between mysql-5.1 and mysql-maria
unittest/mysys/my_atomic-t.c:
  Manual merge between mysql-5.1 and mysql-maria
This commit is contained in:
unknown 2007-09-27 17:05:07 +03:00
commit f4afcec393
314 changed files with 86771 additions and 1781 deletions

View File

@ -1,6 +1,7 @@
*-t
*.Plo
*.Po
*.Tpo
*.a
*.bb
*.bbg
@ -1077,6 +1078,7 @@ libmysqld/ha_innobase.cc
libmysqld/ha_innodb.cc
libmysqld/ha_isam.cc
libmysqld/ha_isammrg.cc
libmysqld/ha_maria.cc
libmysqld/ha_myisam.cc
libmysqld/ha_myisammrg.cc
libmysqld/ha_ndbcluster.cc
@ -1215,6 +1217,7 @@ linked_tools_sources
locked
ltmain.sh
man/*.1
maria_log_control
merge/*.ds?
merge/*.vcproj
missing
@ -2422,6 +2425,43 @@ storage/innobase/ut/.deps/ut0rnd.Po
storage/innobase/ut/.deps/ut0ut.Po
storage/innobase/ut/.deps/ut0vec.Po
storage/innobase/ut/.deps/ut0wqueue.Po
storage/maria/*.MAD
storage/maria/*.MAI
storage/maria/ma_rt_test
storage/maria/ma_sp_test
storage/maria/ma_test1
storage/maria/ma_test2
storage/maria/ma_test3
storage/maria/ma_test_all
storage/maria/maria.log
storage/maria/maria_chk
storage/maria/maria_control
storage/maria/maria_ftdump
storage/maria/maria_log
storage/maria/maria_log.*
storage/maria/maria_pack
storage/maria/maria_read_log
storage/maria/tmp/*
storage/maria/unittest/ma_pagecache_consist_1k-t-big
storage/maria/unittest/ma_pagecache_consist_1kHC-t-big
storage/maria/unittest/ma_pagecache_consist_1kRD-t-big
storage/maria/unittest/ma_pagecache_consist_1kWR-t-big
storage/maria/unittest/ma_pagecache_consist_64k-t-big
storage/maria/unittest/ma_pagecache_consist_64kHC-t-big
storage/maria/unittest/ma_pagecache_consist_64kRD-t-big
storage/maria/unittest/ma_pagecache_consist_64kWR-t-big
storage/maria/unittest/ma_pagecache_single_64k-t-big
storage/maria/unittest/ma_test_loghandler_long-t-big
storage/maria/unittest/maria_control
storage/maria/unittest/mf_pagecache_consist_1k-t-big
storage/maria/unittest/mf_pagecache_consist_1kHC-t-big
storage/maria/unittest/mf_pagecache_consist_1kRD-t-big
storage/maria/unittest/mf_pagecache_consist_1kWR-t-big
storage/maria/unittest/mf_pagecache_consist_64k-t-big
storage/maria/unittest/mf_pagecache_consist_64kHC-t-big
storage/maria/unittest/mf_pagecache_consist_64kRD-t-big
storage/maria/unittest/mf_pagecache_consist_64kWR-t-big
storage/maria/unittest/mf_pagecache_single_64k-t-big
storage/myisam/.deps/ft_boolean_search.Po
storage/myisam/.deps/ft_nlq_search.Po
storage/myisam/.deps/ft_parser.Po
@ -2974,13 +3014,25 @@ unittest/examples/.deps/simple-t.Po
unittest/examples/.deps/skip-t.Po
unittest/examples/.deps/skip_all-t.Po
unittest/examples/.deps/todo-t.Po
unittest/maria_control
unittest/mysys/*.t
unittest/mysys/.deps/base64-t.Po
unittest/mysys/.deps/bitmap-t.Po
unittest/mysys/.deps/my_atomic-t.Po
unittest/mysys/mf_pagecache_consist_1k-t-big
unittest/mysys/mf_pagecache_consist_1kHC-t-big
unittest/mysys/mf_pagecache_consist_1kRD-t-big
unittest/mysys/mf_pagecache_consist_1kWR-t-big
unittest/mysys/mf_pagecache_consist_64k-t-big
unittest/mysys/mf_pagecache_consist_64kHC-t-big
unittest/mysys/mf_pagecache_consist_64kRD-t-big
unittest/mysys/mf_pagecache_consist_64kWR-t-big
unittest/mysys/mf_pagecache_single_64k-t-big
unittest/mytap/.deps/tap.Po
unittest/mytap/t/*.t
unittest/mytap/t/.deps/basic-t.Po
unittest/page_cache_test_file_1
unittest/pagecache_debug.log
unittest/unit
vi.h
vio/*.ds?

0
.tree-is-private Normal file
View File

View File

@ -170,10 +170,10 @@ max_configs="$SSL_LIBRARY --with-plugins=max --with-embedded-server"
# CPU and platform specific compilation flags.
#
alpha_cflags="$check_cpu_cflags -Wa,-m$cpu_flag"
amd64_cflags="$check_cpu_cflags"
amd64_cflags="$check_cpu_cflags -DSTACK_DIRECTION=-1"
amd64_cxxflags="" # If dropping '--with-big-tables', add here "-DBIG_TABLES"
pentium_cflags="$check_cpu_cflags"
pentium64_cflags="$check_cpu_cflags -m64"
pentium_cflags="$check_cpu_cflags -DSTACK_DIRECTION=-1"
pentium64_cflags="$check_cpu_cflags -m64 -DSTACK_DIRECTION=-1"
ppc_cflags="$check_cpu_cflags"
sparc_cflags=""

View File

@ -50,6 +50,7 @@ fi
--with-blackhole-storage-engine \
--with-csv-storage-engine \
--with-example-storage-engine \
--with-maria-storage-engine \
--with-federated-storage-engine \
--with-innodb \
--with-ssl \

View File

@ -5,7 +5,7 @@ FROM=$USER@mysql.com
COMMITS=commits@lists.mysql.com
DOCS=docs-commit@mysql.com
LIMIT=10000
VERSION="5.1"
VERSION="maria"
BKROOT=`bk root`
if [ -x /usr/sbin/sendmail ]; then

View File

@ -20,3 +20,18 @@ then
exit 1
fi
# detect if C/C++ files have new trailing white space
trailingblank=`echo $BK_FILE | egrep '\.(c|.h)'`
if [ -n "$trailingblank" ]
then
trailingblank=`bk diffs $BK_FILE | grep '^> .*[[:space:]]$'`
if [ -n "$trailingblank" ]
then
echo "bk diffs $BK_FILE | grep '^> .*[[:space:]]$'"
echo "reported white space at end of some added/modified lines"
echo ""
echo "Checkin FAILED!"
echo "Fix the problem and retry."
exit 1
fi
fi

View File

@ -95,7 +95,7 @@ test-binlog-statement:
cd mysql-test ; \
@PERL@ ./mysql-test-run.pl $(force) --mysqld=--binlog-format=statement
test: test-unit test-ns test-pr
test: test-ns test-pr
test-full: test test-nr test-ps

View File

@ -63,7 +63,9 @@
enum {
OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION,
OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES
OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR,
OPT_GLOBAL_SUBST
};
static int record= 0, opt_sleep= -1;
@ -104,6 +106,9 @@ static char delimiter[MAX_DELIMITER_LENGTH]= ";";
static uint delimiter_length= 1;
static char TMPDIR[FN_REFLEN];
static char global_subst_from[200];
static char global_subst_to[200];
static char *global_subst= NULL;
/* Block stack */
enum block_cmd {
@ -168,6 +173,10 @@ static void init_re(void);
static int match_re(my_regex_t *, char *);
static void free_re(void);
static int replace(DYNAMIC_STRING *ds_str,
const char *search_str, ulong search_len,
const char *replace_str, ulong replace_len);
DYNAMIC_ARRAY q_lines;
#include "sslopt-vars.h"
@ -1541,6 +1550,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
void check_result(DYNAMIC_STRING* ds)
{
int res;
const char* mess= "Result content mismatch\n";
DBUG_ENTER("check_result");
@ -1550,7 +1560,32 @@ void check_result(DYNAMIC_STRING* ds)
if (access(result_file_name, F_OK) != 0)
die("The specified result file does not exist: '%s'", result_file_name);
switch (dyn_string_cmp(ds, result_file_name)) {
res= dyn_string_cmp(ds, result_file_name);
if (global_subst && res != RESULT_OK)
{
/**
@todo MARIA_HACK
This serves for when a test is run with --default-storage-engine=X
where X is not MyISAM: tests using SHOW CREATE TABLE will always fail
because SHOW CREATE TABLE prints X instead of MyISAM. With
--global-subst=X,MyISAM , such trivial differences are eliminated and
test may be reported as passing.
--global-subst is only a quick way to run a lot of existing tests
with Maria and find bugs; it is not good enough for reaching the main
trees when Maria is merged into them.
--global-subst should be removed.
*/
uint global_subst_from_len= strlen(global_subst_from);
uint global_subst_to_len= strlen(global_subst_to);
while (replace(ds,
global_subst_from, global_subst_from_len,
global_subst_to, global_subst_to_len) == 0)
/* do nothing */ ;
/* let's compare again to see if it is ok now */
res= dyn_string_cmp(ds, result_file_name);
}
switch(res)
{
case RESULT_OK:
break; /* ok */
case RESULT_LENGTH_MISMATCH:
@ -4930,6 +4965,11 @@ static struct my_option my_long_options[] =
{"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
(uchar**) &debug_info_flag, (uchar**) &debug_info_flag,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"global-subst", OPT_GLOBAL_SUBST, "argument should be 'X,Y' ;"
" substitute string X with another Y accross the whole test's current"
" result before comparing with expected result file",
(uchar**) &global_subst, (uchar**) &global_subst, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Connect to host.", (uchar**) &opt_host, (uchar**) &opt_host, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"include", 'i', "Include SQL before each test case.", (uchar**) &opt_include,
@ -5182,6 +5222,16 @@ int parse_args(int argc, char **argv)
if (debug_check_flag)
my_end_arg= MY_CHECK_ERROR;
if (global_subst != NULL)
{
char *comma= strstr(global_subst, ",");
if (comma == NULL)
die("wrong --global-subst, must be X,Y");
memcpy(global_subst_from, global_subst, (comma-global_subst));
global_subst_from[comma-global_subst]= 0;
memcpy(global_subst_to, comma+1, strlen(comma));
}
return 0;
}

View File

@ -2476,8 +2476,6 @@ AC_SUBST(readline_basedir)
AC_SUBST(readline_link)
AC_SUBST(readline_h_ln_cmd)
# Include man pages, if desired, adapted to the configured parts.
if test X"$with_man" = Xyes
then

View File

@ -26,8 +26,8 @@ pkginclude_HEADERS = $(HEADERS_ABI) my_dbug.h m_string.h my_sys.h \
my_getopt.h sslopt-longopts.h my_dir.h \
sslopt-vars.h sslopt-case.h sql_common.h keycache.h \
m_ctype.h my_attribute.h $(HEADERS_GEN)
noinst_HEADERS = config-win.h config-netware.h \
heap.h my_bitmap.h my_uctype.h \
noinst_HEADERS = config-win.h config-netware.h lf.h my_bit.h \
heap.h maria.h myisamchk.h my_bitmap.h my_uctype.h \
myisam.h myisampack.h myisammrg.h ft_global.h\
mysys_err.h my_base.h help_start.h help_end.h \
my_nosys.h my_alarm.h queues.h rijndael.h sha1.h \
@ -36,7 +36,7 @@ noinst_HEADERS = config-win.h config-netware.h \
mysql_version.h.in my_handler.h my_time.h \
my_vle.h my_user.h my_atomic.h atomic/nolock.h \
atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \
my_libwrap.h
my_libwrap.h wqueue.h
# Remove built files and the symlinked directories
CLEANFILES = $(BUILT_SOURCES) readline openssl

View File

@ -13,24 +13,25 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#if defined(__i386__) || defined(_M_IX86)
#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)
#ifdef MY_ATOMIC_MODE_DUMMY
# define LOCK ""
#else
# define LOCK "lock"
#endif
# ifdef MY_ATOMIC_MODE_DUMMY
# define LOCK_prefix ""
# else
# define LOCK_prefix "lock"
# endif
#ifdef __GNUC__
#include "x86-gcc.h"
#elif defined(_MSC_VER)
#include "x86-msvc.h"
#endif
# ifdef __GNUC__
# include "x86-gcc.h"
# elif defined(_MSC_VER)
# error Broken!
# include "x86-msvc.h"
# endif
#endif
#ifdef make_atomic_cas_body
typedef struct { } my_atomic_rwlock_t;
typedef struct { } my_atomic_rwlock_t __attribute__ ((unused));
#define my_atomic_rwlock_destroy(name)
#define my_atomic_rwlock_init(name)
#define my_atomic_rwlock_rdlock(name)

View File

@ -13,7 +13,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t;
typedef struct {pthread_mutex_t rw;} my_atomic_rwlock_t;
#ifdef MY_ATOMIC_MODE_DUMMY
/*
@ -31,17 +31,22 @@ typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t;
#define my_atomic_rwlock_wrunlock(name)
#define MY_ATOMIC_MODE "dummy (non-atomic)"
#else
#define my_atomic_rwlock_destroy(name) pthread_rwlock_destroy(& (name)->rw)
#define my_atomic_rwlock_init(name) pthread_rwlock_init(& (name)->rw, 0)
#define my_atomic_rwlock_rdlock(name) pthread_rwlock_rdlock(& (name)->rw)
#define my_atomic_rwlock_wrlock(name) pthread_rwlock_wrlock(& (name)->rw)
#define my_atomic_rwlock_rdunlock(name) pthread_rwlock_unlock(& (name)->rw)
#define my_atomic_rwlock_wrunlock(name) pthread_rwlock_unlock(& (name)->rw)
#define MY_ATOMIC_MODE "rwlocks"
/*
we're using read-write lock macros but map them to mutex locks, and they're
faster. Still, having semantically rich API we can change the
underlying implementation, if necessary.
*/
#define my_atomic_rwlock_destroy(name) pthread_mutex_destroy(& (name)->rw)
#define my_atomic_rwlock_init(name) pthread_mutex_init(& (name)->rw, 0)
#define my_atomic_rwlock_rdlock(name) pthread_mutex_lock(& (name)->rw)
#define my_atomic_rwlock_wrlock(name) pthread_mutex_lock(& (name)->rw)
#define my_atomic_rwlock_rdunlock(name) pthread_mutex_unlock(& (name)->rw)
#define my_atomic_rwlock_wrunlock(name) pthread_mutex_unlock(& (name)->rw)
#define MY_ATOMIC_MODE "mutex"
#endif
#define make_atomic_add_body(S) int ## S sav; sav= *a; *a+= v; v=sav;
#define make_atomic_swap_body(S) int ## S sav; sav= *a; *a= v; v=sav;
#define make_atomic_fas_body(S) int ## S sav; sav= *a; *a= v; v=sav;
#define make_atomic_cas_body(S) if ((ret= (*a == *cmp))) *a= set; else *cmp=*a;
#define make_atomic_load_body(S) ret= *a;
#define make_atomic_store_body(S) *a= v;

View File

@ -19,10 +19,18 @@
architectures support double-word (128-bit) cas.
*/
#ifdef MY_ATOMIC_NO_XADD
#define MY_ATOMIC_MODE "gcc-x86" LOCK "-no-xadd"
#ifdef __x86_64__
# ifdef MY_ATOMIC_NO_XADD
# define MY_ATOMIC_MODE "gcc-amd64" LOCK_prefix "-no-xadd"
# else
# define MY_ATOMIC_MODE "gcc-amd64" LOCK_prefix
# endif
#else
#define MY_ATOMIC_MODE "gcc-x86" LOCK
# ifdef MY_ATOMIC_NO_XADD
# define MY_ATOMIC_MODE "gcc-x86" LOCK_prefix "-no-xadd"
# else
# define MY_ATOMIC_MODE "gcc-x86" LOCK_prefix
# endif
#endif
/* fix -ansi errors while maintaining readability */
@ -32,12 +40,12 @@
#ifndef MY_ATOMIC_NO_XADD
#define make_atomic_add_body(S) \
asm volatile (LOCK "; xadd %0, %1;" : "+r" (v) , "+m" (*a))
asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a))
#endif
#define make_atomic_swap_body(S) \
asm volatile ("; xchg %0, %1;" : "+r" (v) , "+m" (*a))
#define make_atomic_fas_body(S) \
asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (*a))
#define make_atomic_cas_body(S) \
asm volatile (LOCK "; cmpxchg %3, %0; setz %2;" \
asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \
: "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set))
#ifdef MY_ATOMIC_MODE_DUMMY
@ -46,13 +54,16 @@
#else
/*
Actually 32-bit reads/writes are always atomic on x86
But we add LOCK here anyway to force memory barriers
But we add LOCK_prefix here anyway to force memory barriers
*/
#define make_atomic_load_body(S) \
ret=0; \
asm volatile (LOCK "; cmpxchg %2, %0" \
asm volatile (LOCK_prefix "; cmpxchg %2, %0" \
: "+m" (*a), "+a" (ret): "r" (ret))
#define make_atomic_store_body(S) \
asm volatile ("; xchg %0, %1;" : "+m" (*a) : "r" (v))
asm volatile ("; xchg %0, %1;" : "+m" (*a), "+r" (v))
#endif
/* TODO test on intel whether the below helps. on AMD it makes no difference */
//#define LF_BACKOFF ({asm volatile ("rep; nop"); 1; })

View File

@ -25,24 +25,24 @@
#ifndef _atomic_h_cleanup_
#define _atomic_h_cleanup_ "atomic/x86-msvc.h"
#define MY_ATOMIC_MODE "msvc-x86" LOCK
#define MY_ATOMIC_MODE "msvc-x86" LOCK_prefix
#define make_atomic_add_body(S) \
_asm { \
_asm mov reg_ ## S, v \
_asm LOCK xadd *a, reg_ ## S \
_asm LOCK_prefix xadd *a, reg_ ## S \
_asm movzx v, reg_ ## S \
}
#define make_atomic_cas_body(S) \
_asm { \
_asm mov areg_ ## S, *cmp \
_asm mov reg2_ ## S, set \
_asm LOCK cmpxchg *a, reg2_ ## S \
_asm LOCK_prefix cmpxchg *a, reg2_ ## S \
_asm mov *cmp, areg_ ## S \
_asm setz al \
_asm movzx ret, al \
}
#define make_atomic_swap_body(S) \
#define make_atomic_fas_body(S) \
_asm { \
_asm mov reg_ ## S, v \
_asm xchg *a, reg_ ## S \
@ -55,13 +55,13 @@
#else
/*
Actually 32-bit reads/writes are always atomic on x86
But we add LOCK here anyway to force memory barriers
But we add LOCK_prefix here anyway to force memory barriers
*/
#define make_atomic_load_body(S) \
_asm { \
_asm mov areg_ ## S, 0 \
_asm mov reg2_ ## S, areg_ ## S \
_asm LOCK cmpxchg *a, reg2_ ## S \
_asm LOCK_prefix cmpxchg *a, reg2_ ## S \
_asm mov ret, areg_ ## S \
}
#define make_atomic_store_body(S) \

View File

@ -65,6 +65,17 @@ void ft_free_stopwords(void);
FT_INFO *ft_init_search(uint,void *, uint, uchar *, uint,CHARSET_INFO *, uchar *);
my_bool ft_boolean_check_syntax_string(const uchar *);
/* Internal symbols for fulltext between maria and MyISAM */
#define HA_FT_WTYPE HA_KEYTYPE_FLOAT
#define HA_FT_WLEN 4
#define FT_SEGS 2
#define ft_sintXkorr(A) mi_sint4korr(A)
#define ft_intXstore(T,A) mi_int4store(T,A)
extern const HA_KEYSEG ft_keysegs[FT_SEGS];
#ifdef __cplusplus
}
#endif

View File

@ -132,7 +132,8 @@ extern void end_key_cache(KEY_CACHE *keycache, my_bool cleanup);
/* Functions to handle multiple key caches */
extern my_bool multi_keycache_init(void);
extern void multi_keycache_free(void);
extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length);
extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length,
KEY_CACHE *def);
extern my_bool multi_key_cache_set(const uchar *key, uint length,
KEY_CACHE *key_cache);
extern void multi_key_cache_change(KEY_CACHE *old_data,

260
include/lf.h Normal file
View File

@ -0,0 +1,260 @@
/* Copyright (C) 2007 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _lf_h
#define _lf_h
#include <my_atomic.h>
/*
Helpers to define both func() and _func(), where
func() is a _func() protected by my_atomic_rwlock_wrlock()
*/
#define lock_wrap(f, t, proto_args, args, lock) \
t _ ## f proto_args; \
static inline t f proto_args \
{ \
t ret; \
my_atomic_rwlock_wrlock(lock); \
ret= _ ## f args; \
my_atomic_rwlock_wrunlock(lock); \
return ret; \
}
#define lock_wrap_void(f, proto_args, args, lock) \
void _ ## f proto_args; \
static inline void f proto_args \
{ \
my_atomic_rwlock_wrlock(lock); \
_ ## f args; \
my_atomic_rwlock_wrunlock(lock); \
}
#define nolock_wrap(f, t, proto_args, args) \
t _ ## f proto_args; \
static inline t f proto_args \
{ \
return _ ## f args; \
}
#define nolock_wrap_void(f, proto_args, args) \
void _ ## f proto_args; \
static inline void f proto_args \
{ \
_ ## f args; \
}
/*
wait-free dynamic array, see lf_dynarray.c
4 levels of 256 elements each mean 4311810304 elements in an array - it
should be enough for a while
*/
#define LF_DYNARRAY_LEVEL_LENGTH 256
#define LF_DYNARRAY_LEVELS 4
typedef struct {
void * volatile level[LF_DYNARRAY_LEVELS];
uint size_of_element;
my_atomic_rwlock_t lock;
} LF_DYNARRAY;
typedef int (*lf_dynarray_func)(void *, void *);
void lf_dynarray_init(LF_DYNARRAY *array, uint element_size);
void lf_dynarray_destroy(LF_DYNARRAY *array);
nolock_wrap(lf_dynarray_value, void *,
(LF_DYNARRAY *array, uint idx),
(array, idx))
lock_wrap(lf_dynarray_lvalue, void *,
(LF_DYNARRAY *array, uint idx),
(array, idx),
&array->lock)
nolock_wrap(lf_dynarray_iterate, int,
(LF_DYNARRAY *array, lf_dynarray_func func, void *arg),
(array, func, arg))
/*
pin manager for memory allocator, lf_alloc-pin.c
*/
#define LF_PINBOX_PINS 4
#define LF_PURGATORY_SIZE 10
typedef void lf_pinbox_free_func(void *, void *, void*);
typedef struct {
LF_DYNARRAY pinarray;
lf_pinbox_free_func *free_func;
void *free_func_arg;
uint free_ptr_offset;
uint32 volatile pinstack_top_ver; /* this is a versioned pointer */
uint32 volatile pins_in_array; /* number of elements in array */
} LF_PINBOX;
typedef struct {
void * volatile pin[LF_PINBOX_PINS];
LF_PINBOX *pinbox;
void *stack_ends_here;
void *purgatory;
uint32 purgatory_count;
uint32 volatile link;
/* we want sizeof(LF_PINS) to be 128 to avoid false sharing */
char pad[128-sizeof(uint32)*2
-sizeof(LF_PINBOX *)
-sizeof(void*)
-sizeof(void *)*(LF_PINBOX_PINS+1)];
} LF_PINS;
/*
shortcut macros to do an atomic_wrlock on a structure that uses pins
(e.g. lf_hash).
*/
#define lf_rwlock_by_pins(PINS) \
my_atomic_rwlock_wrlock(&(PINS)->pinbox->pinarray.lock)
#define lf_rwunlock_by_pins(PINS) \
my_atomic_rwlock_wrunlock(&(PINS)->pinbox->pinarray.lock)
/*
compile-time assert, to require "no less than N" pins
it's enough if it'll fail on at least one compiler, so
we'll enable it on GCC only, which supports zero-length arrays.
*/
#if defined(__GNUC__) && defined(MY_LF_EXTRA_DEBUG)
#define LF_REQUIRE_PINS(N) \
static const char require_pins[LF_PINBOX_PINS-N] \
__attribute__ ((unused)); \
static const int LF_NUM_PINS_IN_THIS_FILE= N;
#define _lf_pin(PINS, PIN, ADDR) \
( \
assert(PIN < LF_NUM_PINS_IN_THIS_FILE), \
my_atomic_storeptr(&(PINS)->pin[PIN], (ADDR)) \
)
#else
#define LF_REQUIRE_PINS(N)
#define _lf_pin(PINS, PIN, ADDR) my_atomic_storeptr(&(PINS)->pin[PIN], (ADDR))
#endif
#define _lf_unpin(PINS, PIN) _lf_pin(PINS, PIN, NULL)
#define lf_pin(PINS, PIN, ADDR) \
do { \
lf_rwlock_by_pins(PINS); \
_lf_pin(PINS, PIN, ADDR); \
lf_rwunlock_by_pins(PINS); \
} while (0)
#define lf_unpin(PINS, PIN) lf_pin(PINS, PIN, NULL)
#define _lf_assert_pin(PINS, PIN) assert((PINS)->pin[PIN] != 0)
#define _lf_assert_unpin(PINS, PIN) assert((PINS)->pin[PIN] == 0)
void lf_pinbox_init(LF_PINBOX *pinbox, uint free_ptr_offset,
lf_pinbox_free_func *free_func, void * free_func_arg);
void lf_pinbox_destroy(LF_PINBOX *pinbox);
lock_wrap(lf_pinbox_get_pins, LF_PINS *,
(LF_PINBOX *pinbox, void *stack_end),
(pinbox, stack_end),
&pinbox->pinarray.lock);
lock_wrap_void(lf_pinbox_put_pins,
(LF_PINS *pins),
(pins),
&pins->pinbox->pinarray.lock);
lock_wrap_void(lf_pinbox_free,
(LF_PINS *pins, void *addr),
(pins, addr),
&pins->pinbox->pinarray.lock);
/*
memory allocator, lf_alloc-pin.c
*/
struct st_lf_alloc_node {
struct st_lf_alloc_node *next;
};
typedef struct st_lf_allocator {
LF_PINBOX pinbox;
struct st_lf_alloc_node * volatile top;
uint element_size;
uint32 volatile mallocs;
} LF_ALLOCATOR;
void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset);
void lf_alloc_destroy(LF_ALLOCATOR *allocator);
uint lf_alloc_pool_count(LF_ALLOCATOR *allocator);
/*
shortcut macros to access underlying pinbox functions from an LF_ALLOCATOR
see _lf_pinbox_get_pins() and _lf_pinbox_put_pins()
*/
#define _lf_alloc_free(PINS, PTR) _lf_pinbox_free((PINS), (PTR))
#define lf_alloc_free(PINS, PTR) lf_pinbox_free((PINS), (PTR))
#define _lf_alloc_get_pins(A, ST) _lf_pinbox_get_pins(&(A)->pinbox, (ST))
#define lf_alloc_get_pins(A, ST) lf_pinbox_get_pins(&(A)->pinbox, (ST))
#define _lf_alloc_put_pins(PINS) _lf_pinbox_put_pins(PINS)
#define lf_alloc_put_pins(PINS) lf_pinbox_put_pins(PINS)
#define lf_alloc_direct_free(ALLOC, ADDR) my_free((uchar*)(ADDR), MYF(0))
lock_wrap(lf_alloc_new, void *,
(LF_PINS *pins),
(pins),
&pins->pinbox->pinarray.lock);
/*
extendible hash, lf_hash.c
*/
#include <hash.h>
#define LF_HASH_UNIQUE 1
typedef struct {
LF_DYNARRAY array; /* hash itself */
LF_ALLOCATOR alloc; /* allocator for elements */
hash_get_key get_key; /* see HASH */
CHARSET_INFO *charset; /* see HASH */
uint key_offset, key_length; /* see HASH */
uint element_size, flags; /* LF_HASH_UNIQUE, etc */
int32 volatile size; /* size of array */
int32 volatile count; /* number of elements in the hash */
} LF_HASH;
void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
uint key_offset, uint key_length, hash_get_key get_key,
CHARSET_INFO *charset);
void lf_hash_destroy(LF_HASH *hash);
int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data);
void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen);
int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen);
/*
shortcut macros to access underlying pinbox functions from an LF_HASH
see _lf_pinbox_get_pins() and _lf_pinbox_put_pins()
*/
#define _lf_hash_get_pins(HASH, ST) _lf_alloc_get_pins(&(HASH)->alloc, (ST))
#define lf_hash_get_pins(HASH, ST) lf_alloc_get_pins(&(HASH)->alloc, (ST))
#define _lf_hash_put_pins(PINS) _lf_pinbox_put_pins(PINS)
#define lf_hash_put_pins(PINS) lf_pinbox_put_pins(PINS)
#define lf_hash_search_unpin(PINS) lf_unpin((PINS), 2)
/*
cleanup
*/
#undef lock_wrap_void
#undef lock_wrap
#undef nolock_wrap_void
#undef nolock_wrap
#endif

View File

@ -67,7 +67,7 @@
# define bcopy(s, d, n) memcpy((d), (s), (n))
# define bcmp(A,B,C) memcmp((A),(B),(C))
# define bzero(A,B) memset((A),0,(B))
# define bmove_align(A,B,C) memcpy((A),(B),(C))
# define bmove_align(A,B,C) memcpy((A),(B),(C))
#endif
#if defined(__cplusplus)
@ -129,7 +129,10 @@ extern size_t bcmp(const uchar *s1,const uchar *s2,size_t len);
extern size_t my_bcmp(const uchar *s1,const uchar *s2,size_t len);
#undef bcmp
#define bcmp(A,B,C) my_bcmp((A),(B),(C))
#endif
#define bzero_if_purify(A,B) bzero(A,B)
#else
#define bzero_if_purify(A,B)
#endif /* HAVE_purify */
#ifndef bmove512
extern void bmove512(uchar *dst,const uchar *src,size_t len);

444
include/maria.h Normal file
View File

@ -0,0 +1,444 @@
/* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* This file should be included when using maria_funktions */
#ifndef _maria_h
#define _maria_h
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _my_base_h
#include <my_base.h>
#endif
#ifndef _m_ctype_h
#include <m_ctype.h>
#endif
#include "../storage/maria/ma_pagecache.h"
#include "my_handler.h"
#include "ft_global.h"
#include <myisamchk.h>
#include <mysql/plugin.h>
/*
Limit max keys according to HA_MAX_POSSIBLE_KEY; See myisamchk.h for details
*/
#if MAX_INDEXES > HA_MAX_POSSIBLE_KEY
#define MARIA_MAX_KEY HA_MAX_POSSIBLE_KEY /* Max allowed keys */
#else
#define MARIA_MAX_KEY MAX_INDEXES /* Max allowed keys */
#endif
#define MARIA_MAX_MSG_BUF 1024 /* used in CHECK TABLE, REPAIR TABLE */
#define MARIA_NAME_IEXT ".MAI"
#define MARIA_NAME_DEXT ".MAD"
/* Max extra space to use when sorting keys */
#define MARIA_MAX_TEMP_LENGTH 2*1024L*1024L*1024L
/* Possible values for maria_block_size (must be power of 2) */
#define MARIA_KEY_BLOCK_LENGTH 8192 /* default key block length */
#define MARIA_MIN_KEY_BLOCK_LENGTH 1024 /* Min key block length */
#define MARIA_MAX_KEY_BLOCK_LENGTH 32768
/* Minimal page cache when we only want to be able to scan a table */
#define MARIA_MIN_PAGE_CACHE_SIZE 65536
/*
In the following macros '_keyno_' is 0 .. keys-1.
If there can be more keys than bits in the key_map, the highest bit
is for all upper keys. They cannot be switched individually.
This means that clearing of high keys is ignored, setting one high key
sets all high keys.
*/
#define MARIA_KEYMAP_BITS (8 * SIZEOF_LONG_LONG)
#define MARIA_KEYMAP_HIGH_MASK (ULL(1) << (MARIA_KEYMAP_BITS - 1))
#define maria_get_mask_all_keys_active(_keys_) \
(((_keys_) < MARIA_KEYMAP_BITS) ? \
((ULL(1) << (_keys_)) - ULL(1)) : \
(~ ULL(0)))
#if MARIA_MAX_KEY > MARIA_KEYMAP_BITS
#define maria_is_key_active(_keymap_,_keyno_) \
(((_keyno_) < MARIA_KEYMAP_BITS) ? \
test((_keymap_) & (ULL(1) << (_keyno_))) : \
test((_keymap_) & MARIA_KEYMAP_HIGH_MASK))
#define maria_set_key_active(_keymap_,_keyno_) \
(_keymap_)|= (((_keyno_) < MARIA_KEYMAP_BITS) ? \
(ULL(1) << (_keyno_)) : \
MARIA_KEYMAP_HIGH_MASK)
#define maria_clear_key_active(_keymap_,_keyno_) \
(_keymap_)&= (((_keyno_) < MARIA_KEYMAP_BITS) ? \
(~ (ULL(1) << (_keyno_))) : \
(~ (ULL(0))) /*ignore*/ )
#else
#define maria_is_key_active(_keymap_,_keyno_) \
test((_keymap_) & (ULL(1) << (_keyno_)))
#define maria_set_key_active(_keymap_,_keyno_) \
(_keymap_)|= (ULL(1) << (_keyno_))
#define maria_clear_key_active(_keymap_,_keyno_) \
(_keymap_)&= (~ (ULL(1) << (_keyno_)))
#endif
#define maria_is_any_key_active(_keymap_) \
test((_keymap_))
#define maria_is_all_keys_active(_keymap_,_keys_) \
((_keymap_) == maria_get_mask_all_keys_active(_keys_))
#define maria_set_all_keys_active(_keymap_,_keys_) \
(_keymap_)= maria_get_mask_all_keys_active(_keys_)
#define maria_clear_all_keys_active(_keymap_) \
(_keymap_)= 0
#define maria_intersect_keys_active(_to_,_from_) \
(_to_)&= (_from_)
#define maria_is_any_intersect_keys_active(_keymap1_,_keys_,_keymap2_) \
((_keymap1_) & (_keymap2_) & \
maria_get_mask_all_keys_active(_keys_))
#define maria_copy_keys_active(_to_,_maxkeys_,_from_) \
(_to_)= (maria_get_mask_all_keys_active(_maxkeys_) & \
(_from_))
/* Param to/from maria_info */
typedef ulonglong MARIA_RECORD_POS;
typedef struct st_maria_isaminfo /* Struct from h_info */
{
ha_rows records; /* Records in database */
ha_rows deleted; /* Deleted records in database */
MARIA_RECORD_POS recpos; /* Pos for last used record */
MARIA_RECORD_POS newrecpos; /* Pos if we write new record */
MARIA_RECORD_POS dup_key_pos; /* Position to record with dup key */
my_off_t data_file_length; /* Length of data file */
my_off_t max_data_file_length, index_file_length;
my_off_t max_index_file_length, delete_length;
ulonglong auto_increment;
ulonglong key_map; /* Which keys are used */
time_t create_time; /* When table was created */
time_t check_time;
time_t update_time;
ulong record_offset;
ulong *rec_per_key; /* for sql optimizing */
ulong reclength; /* Recordlength */
ulong mean_reclength; /* Mean recordlength (if packed) */
char *data_file_name, *index_file_name;
enum data_file_type data_file_type;
uint keys; /* Number of keys in use */
uint options; /* HA_OPTION_... used */
uint reflength;
int errkey, /* With key was dupplicated on err */
sortkey; /* clustered by this key */
File filenr; /* (uniq) filenr for datafile */
} MARIA_INFO;
typedef struct st_maria_create_info
{
const char *index_file_name, *data_file_name; /* If using symlinks */
ha_rows max_rows;
ha_rows reloc_rows;
ulonglong auto_increment;
ulonglong data_file_length;
ulonglong key_file_length;
/* Size of null bitmap at start of row */
uint null_bytes;
uint old_options;
enum data_file_type org_data_file_type;
uint8 language;
my_bool with_auto_increment, transactional;
} MARIA_CREATE_INFO;
struct st_maria_info; /* For referense */
struct st_maria_share;
typedef struct st_maria_info MARIA_HA;
struct st_maria_s_param;
typedef struct st_maria_keydef /* Key definition with open & info */
{
struct st_maria_share *share; /* Pointer to base (set in open) */
uint16 keysegs; /* Number of key-segment */
uint16 flag; /* NOSAME, PACK_USED */
uint8 key_alg; /* BTREE, RTREE */
uint16 block_length; /* Length of keyblock (auto) */
uint16 underflow_block_length; /* When to execute underflow */
uint16 keylength; /* Tot length of keyparts (auto) */
uint16 minlength; /* min length of (packed) key (auto) */
uint16 maxlength; /* max length of (packed) key (auto) */
uint32 version; /* For concurrent read/write */
uint32 ftparser_nr; /* distinct ftparser number */
HA_KEYSEG *seg, *end;
struct st_mysql_ftparser *parser; /* Fulltext [pre]parser */
int (*bin_search)(struct st_maria_info *info,
struct st_maria_keydef *keyinfo, uchar *page, uchar *key,
uint key_len, uint comp_flag, uchar **ret_pos,
uchar *buff, my_bool *was_last_key);
uint(*get_key)(struct st_maria_keydef *keyinfo, uint nod_flag,
uchar **page, uchar *key);
int (*pack_key)(struct st_maria_keydef *keyinfo, uint nod_flag,
uchar *next_key, uchar *org_key, uchar *prev_key,
const uchar *key, struct st_maria_s_param *s_temp);
void (*store_key)(struct st_maria_keydef *keyinfo, uchar *key_pos,
struct st_maria_s_param *s_temp);
int (*ck_insert)(struct st_maria_info *inf, uint k_nr, uchar *k, uint klen);
int (*ck_delete)(struct st_maria_info *inf, uint k_nr, uchar *k, uint klen);
} MARIA_KEYDEF;
#define MARIA_UNIQUE_HASH_LENGTH 4
typedef struct st_maria_unique_def /* Segment definition of unique */
{
uint16 keysegs; /* Number of key-segment */
uint8 key; /* Mapped to which key */
uint8 null_are_equal;
HA_KEYSEG *seg, *end;
} MARIA_UNIQUEDEF;
typedef struct st_maria_decode_tree /* Decode huff-table */
{
uint16 *table;
uint quick_table_bits;
uchar *intervalls;
} MARIA_DECODE_TREE;
struct st_maria_bit_buff;
/*
Note that null markers should always be first in a row !
When creating a column, one should only specify:
type, length, null_bit and null_pos
*/
typedef struct st_maria_columndef /* column information */
{
uint64 offset; /* Offset to position in row */
enum en_fieldtype type;
uint16 length; /* length of field */
/* Intern variable (size of total storage area for the row) */
uint16 fill_length;
uint16 null_pos; /* Position for null marker */
uint16 empty_pos; /* Position for empty marker */
uint8 null_bit; /* If column may be NULL */
/* Intern. Set if column should be zero packed (part of empty_bits) */
uint8 empty_bit;
#ifndef NOT_PACKED_DATABASES
void(*unpack)(struct st_maria_columndef *rec,
struct st_maria_bit_buff *buff,
uchar *start, uchar *end);
enum en_fieldtype base_type;
uint space_length_bits, pack_type;
MARIA_DECODE_TREE *huff_tree;
#endif
} MARIA_COLUMNDEF;
extern ulong maria_block_size;
extern ulong maria_concurrent_insert;
extern my_bool maria_flush, maria_single_user;
extern my_bool maria_delay_key_write;
extern my_off_t maria_max_temp_length;
extern ulong maria_bulk_insert_tree_size, maria_data_pointer_size;
extern PAGECACHE maria_pagecache_var, *maria_pagecache;
/* Prototypes for maria-functions */
extern int maria_init(void);
extern void maria_end(void);
extern int maria_close(struct st_maria_info *file);
extern int maria_delete(struct st_maria_info *file, const uchar *buff);
extern struct st_maria_info *maria_open(const char *name, int mode,
uint wait_if_locked);
extern struct st_maria_info *maria_clone(struct st_maria_share *share, int mode);
extern int maria_panic(enum ha_panic_function function);
extern int maria_rfirst(struct st_maria_info *file, uchar *buf, int inx);
extern int maria_rkey(struct st_maria_info *file, uchar *buf, int inx,
const uchar *key, key_part_map keypart_map,
enum ha_rkey_function search_flag);
extern int maria_rlast(struct st_maria_info *file, uchar *buf, int inx);
extern int maria_rnext(struct st_maria_info *file, uchar *buf, int inx);
extern int maria_rnext_same(struct st_maria_info *info, uchar *buf);
extern int maria_rprev(struct st_maria_info *file, uchar *buf, int inx);
extern int maria_rrnd(struct st_maria_info *file, uchar *buf,
MARIA_RECORD_POS pos);
extern int maria_scan_init(struct st_maria_info *file);
extern int maria_scan(struct st_maria_info *file, uchar *buf);
extern void maria_scan_end(struct st_maria_info *file);
extern int maria_rsame(struct st_maria_info *file, uchar *record, int inx);
extern int maria_rsame_with_pos(struct st_maria_info *file, uchar *record,
int inx, MARIA_RECORD_POS pos);
extern int maria_update(struct st_maria_info *file, const uchar *old,
uchar *new_record);
extern int maria_write(struct st_maria_info *file, uchar *buff);
extern MARIA_RECORD_POS maria_position(struct st_maria_info *file);
extern int maria_status(struct st_maria_info *info, MARIA_INFO *x, uint flag);
extern int maria_lock_database(struct st_maria_info *file, int lock_type);
extern int maria_create(const char *name, enum data_file_type record_type,
uint keys, MARIA_KEYDEF *keydef,
uint columns, MARIA_COLUMNDEF *columndef,
uint uniques, MARIA_UNIQUEDEF *uniquedef,
MARIA_CREATE_INFO *create_info, uint flags);
extern int maria_delete_table(const char *name);
extern int maria_rename(const char *from, const char *to);
extern int maria_extra(struct st_maria_info *file,
enum ha_extra_function function, void *extra_arg);
extern int maria_reset(struct st_maria_info *file);
extern ha_rows maria_records_in_range(struct st_maria_info *info, int inx,
key_range *min_key, key_range *max_key);
extern int maria_is_changed(struct st_maria_info *info);
extern int maria_delete_all_rows(struct st_maria_info *info);
extern uint maria_get_pointer_length(ulonglong file_length, uint def);
extern int maria_commit(struct st_maria_info *info);
extern int maria_begin(struct st_maria_info *info);
/* this is used to pass to mysql_mariachk_table */
#define MARIA_CHK_REPAIR 1 /* equivalent to mariachk -r */
#define MARIA_CHK_VERIFY 2 /* Verify, run repair if failure */
typedef uint maria_bit_type;
typedef struct st_maria_bit_buff
{ /* Used for packing of record */
maria_bit_type current_byte;
uint bits;
uchar *pos, *end, *blob_pos, *blob_end;
uint error;
} MARIA_BIT_BUFF;
typedef struct st_maria_sort_info
{
#ifdef THREAD
/* sync things */
pthread_mutex_t mutex;
pthread_cond_t cond;
#endif
MARIA_HA *info, *new_info;
HA_CHECK *param;
char *buff;
SORT_KEY_BLOCKS *key_block, *key_block_end;
SORT_FT_BUF *ft_buf;
my_off_t filelength, dupp, buff_length;
ulonglong page;
ha_rows max_records;
uint current_key, total_keys;
uint got_error, threads_running;
myf myf_rw;
enum data_file_type new_data_file_type, org_data_file_type;
} MARIA_SORT_INFO;
typedef struct st_maria_sort_param
{
pthread_t thr;
IO_CACHE read_cache, tempfile, tempfile_for_exceptions;
DYNAMIC_ARRAY buffpek;
MARIA_BIT_BUFF bit_buff; /* For parallel repair of packrec. */
MARIA_KEYDEF *keyinfo;
MARIA_SORT_INFO *sort_info;
HA_KEYSEG *seg;
uchar **sort_keys;
uchar *rec_buff;
void *wordlist, *wordptr;
MEM_ROOT wordroot;
char *record;
MY_TMPDIR *tmpdir;
/*
The next two are used to collect statistics, see maria_update_key_parts for
description.
*/
ulonglong unique[HA_MAX_KEY_SEG+1];
ulonglong notnull[HA_MAX_KEY_SEG+1];
MARIA_RECORD_POS pos,max_pos,filepos,start_recpos;
uint key, key_length,real_key_length,sortbuff_size;
uint maxbuffers, keys, find_length, sort_keys_length;
my_bool fix_datafile, master;
my_bool calc_checksum; /* calculate table checksum */
size_t rec_buff_size;
int (*key_cmp)(struct st_maria_sort_param *, const void *, const void *);
int (*key_read)(struct st_maria_sort_param *, uchar *);
int (*key_write)(struct st_maria_sort_param *, const uchar *);
void (*lock_in_memory)(HA_CHECK *);
NEAR int (*write_keys)(struct st_maria_sort_param *, register uchar **,
uint , struct st_buffpek *, IO_CACHE *);
NEAR uint (*read_to_buffer)(IO_CACHE *,struct st_buffpek *, uint);
NEAR int (*write_key)(struct st_maria_sort_param *, IO_CACHE *,char *,
uint, uint);
} MARIA_SORT_PARAM;
/* functions in maria_check */
void maria_chk_init(HA_CHECK *param);
int maria_chk_status(HA_CHECK *param, MARIA_HA *info);
int maria_chk_del(HA_CHECK *param, register MARIA_HA *info, uint test_flag);
int maria_chk_size(HA_CHECK *param, MARIA_HA *info);
int maria_chk_key(HA_CHECK *param, MARIA_HA *info);
int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, int extend);
int maria_repair(HA_CHECK *param, register MARIA_HA *info,
char * name, int rep_quick);
int maria_sort_index(HA_CHECK *param, register MARIA_HA *info,
char * name);
int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
const char *name, int rep_quick);
int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
const char *name, int rep_quick);
int maria_change_to_newfile(const char *filename, const char *old_ext,
const char *new_ext, myf myflags);
void maria_lock_memory(HA_CHECK *param);
int maria_update_state_info(HA_CHECK *param, MARIA_HA *info, uint update);
void maria_update_key_parts(MARIA_KEYDEF *keyinfo, ulong *rec_per_key_part,
ulonglong *unique, ulonglong *notnull,
ulonglong records);
int maria_filecopy(HA_CHECK *param, File to, File from, my_off_t start,
my_off_t length, const char *type);
int maria_movepoint(MARIA_HA *info, uchar *record, my_off_t oldpos,
my_off_t newpos, uint prot_key);
int maria_write_data_suffix(MARIA_SORT_INFO *sort_info, my_bool fix_datafile);
int maria_test_if_almost_full(MARIA_HA *info);
int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename);
int maria_disable_indexes(MARIA_HA *info);
int maria_enable_indexes(MARIA_HA *info);
int maria_indexes_are_disabled(MARIA_HA *info);
void maria_disable_non_unique_index(MARIA_HA *info, ha_rows rows);
my_bool maria_test_if_sort_rep(MARIA_HA *info, ha_rows rows, ulonglong key_map,
my_bool force);
int maria_init_bulk_insert(MARIA_HA *info, ulong cache_size, ha_rows rows);
void maria_flush_bulk_insert(MARIA_HA *info, uint inx);
void maria_end_bulk_insert(MARIA_HA *info);
int maria_assign_to_pagecache(MARIA_HA *info, ulonglong key_map,
PAGECACHE *key_cache);
void maria_change_pagecache(PAGECACHE *old_key_cache,
PAGECACHE *new_key_cache);
int maria_preload(MARIA_HA *info, ulonglong key_map, my_bool ignore_leaves);
/* fulltext functions */
FT_INFO *maria_ft_init_search(uint,void *, uint, uchar *, uint,
CHARSET_INFO *, uchar *);
/* 'Almost-internal' Maria functions */
void _ma_update_auto_increment_key(HA_CHECK *param, MARIA_HA *info,
my_bool repair);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -13,6 +13,40 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
This header defines five atomic operations:
my_atomic_add#(&var, what)
add 'what' to *var, and return the old value of *var
my_atomic_fas#(&var, what)
'Fetch And Store'
store 'what' in *var, and return the old value of *var
my_atomic_cas#(&var, &old, new)
'Compare And Swap'
if *var is equal to *old, then store 'new' in *var, and return TRUE
otherwise store *var in *old, and return FALSE
my_atomic_load#(&var)
return *var
my_atomic_store#(&var, what)
store 'what' in *var
'#' is substituted by a size suffix - 8, 16, 32, or ptr
(e.g. my_atomic_add8, my_atomic_fas32, my_atomic_casptr).
NOTE This operations are not always atomic, so they always must be
enclosed in my_atomic_rwlock_rdlock(lock)/my_atomic_rwlock_rdunlock(lock)
or my_atomic_rwlock_wrlock(lock)/my_atomic_rwlock_wrunlock(lock).
Hint: if a code block makes intensive use of atomic ops, it make sense
to take/release rwlock once for the whole block, not for every statement.
On architectures where these operations are really atomic, rwlocks will
be optimized away.
*/
#ifndef my_atomic_rwlock_init
#define intptr void *
@ -26,70 +60,115 @@
#endif
#ifndef make_atomic_add_body
#define make_atomic_add_body(S) \
#define make_atomic_add_body(S) \
int ## S tmp=*a; \
while (!my_atomic_cas ## S(a, &tmp, tmp+v)); \
v=tmp;
#endif
#ifdef __GNUC__
/*
we want to be able to use my_atomic_xxx functions with
both signed and unsigned integers. But gcc will issue a warning
"passing arg N of `my_atomic_XXX' as [un]signed due to prototype"
if the signedness of the argument doesn't match the prototype, or
"pointer targets in passing argument N of my_atomic_XXX differ in signedness"
if int* is used where uint* is expected (or vice versa).
Let's shut these warnings up
*/
#define make_transparent_unions(S) \
typedef union { \
int ## S i; \
uint ## S u; \
} U_ ## S __attribute__ ((transparent_union)); \
typedef union { \
int ## S volatile *i; \
uint ## S volatile *u; \
} Uv_ ## S __attribute__ ((transparent_union));
#define uintptr intptr
make_transparent_unions(8)
make_transparent_unions(16)
make_transparent_unions(32)
make_transparent_unions(ptr)
#undef uintptr
#undef make_transparent_unions
#define a U_a.i
#define cmp U_cmp.i
#define v U_v.i
#define set U_set.i
#else
#define U_8 int8
#define U_16 int16
#define U_32 int32
#define U_ptr intptr
#define Uv_8 int8
#define Uv_16 int16
#define Uv_32 int32
#define Uv_ptr intptr
#define U_a volatile *a
#define U_cmp *cmp
#define U_v v
#define U_set set
#endif /* __GCC__ transparent_union magic */
#ifdef HAVE_INLINE
#define make_atomic_add(S) \
static inline int ## S my_atomic_add ## S( \
int ## S volatile *a, int ## S v) \
{ \
make_atomic_add_body(S); \
return v; \
#define make_atomic_add(S) \
STATIC_INLINE int ## S my_atomic_add ## S( \
Uv_ ## S U_a, U_ ## S U_v) \
{ \
make_atomic_add_body(S); \
return v; \
}
#define make_atomic_swap(S) \
static inline int ## S my_atomic_swap ## S( \
int ## S volatile *a, int ## S v) \
{ \
make_atomic_swap_body(S); \
return v; \
#define make_atomic_fas(S) \
STATIC_INLINE int ## S my_atomic_fas ## S( \
Uv_ ## S U_a, U_ ## S U_v) \
{ \
make_atomic_fas_body(S); \
return v; \
}
#define make_atomic_cas(S) \
static inline int my_atomic_cas ## S(int ## S volatile *a, \
int ## S *cmp, int ## S set) \
{ \
int8 ret; \
make_atomic_cas_body(S); \
return ret; \
#define make_atomic_cas(S) \
STATIC_INLINE int my_atomic_cas ## S(Uv_ ## S U_a, \
Uv_ ## S U_cmp, U_ ## S U_set) \
{ \
int8 ret; \
make_atomic_cas_body(S); \
return ret; \
}
#define make_atomic_load(S) \
static inline int ## S my_atomic_load ## S(int ## S volatile *a) \
{ \
int ## S ret; \
make_atomic_load_body(S); \
return ret; \
#define make_atomic_load(S) \
STATIC_INLINE int ## S my_atomic_load ## S(Uv_ ## S U_a) \
{ \
int ## S ret; \
make_atomic_load_body(S); \
return ret; \
}
#define make_atomic_store(S) \
static inline void my_atomic_store ## S( \
int ## S volatile *a, int ## S v) \
{ \
make_atomic_store_body(S); \
#define make_atomic_store(S) \
STATIC_INLINE void my_atomic_store ## S( \
Uv_ ## S U_a, U_ ## S U_v) \
{ \
make_atomic_store_body(S); \
}
#else /* no inline functions */
#define make_atomic_add(S) \
extern int ## S my_atomic_add ## S(int ## S volatile *a, int ## S v);
#define make_atomic_add(S) \
extern int ## S my_atomic_add ## S(Uv_ ## S, U_ ## S);
#define make_atomic_swap(S) \
extern int ## S my_atomic_swap ## S(int ## S volatile *a, int ## S v);
#define make_atomic_fas(S) \
extern int ## S my_atomic_fas ## S(Uv_ ## S, U_ ## S);
#define make_atomic_cas(S) \
extern int my_atomic_cas ## S(int ## S volatile *a, int ## S *cmp, int ## S set);
#define make_atomic_cas(S) \
extern int my_atomic_cas ## S(Uv_ ## S, Uv_ ## S, U_ ## S);
#define make_atomic_load(S) \
extern int ## S my_atomic_load ## S(int ## S volatile *a);
#define make_atomic_load(S) \
extern int ## S my_atomic_load ## S(Uv_ ## S);
#define make_atomic_store(S) \
extern void my_atomic_store ## S(int ## S volatile *a, int ## S v);
#define make_atomic_store(S) \
extern void my_atomic_store ## S(Uv_ ## S, U_ ## S);
#endif
@ -112,28 +191,49 @@ make_atomic_store(16)
make_atomic_store(32)
make_atomic_store(ptr)
make_atomic_swap( 8)
make_atomic_swap(16)
make_atomic_swap(32)
make_atomic_swap(ptr)
#undef make_atomic_add
#undef make_atomic_cas
#undef make_atomic_load
#undef make_atomic_store
#undef make_atomic_swap
#undef make_atomic_add_body
#undef make_atomic_cas_body
#undef make_atomic_load_body
#undef make_atomic_store_body
#undef make_atomic_swap_body
#undef intptr
make_atomic_fas( 8)
make_atomic_fas(16)
make_atomic_fas(32)
make_atomic_fas(ptr)
#ifdef _atomic_h_cleanup_
#include _atomic_h_cleanup_
#undef _atomic_h_cleanup_
#endif
#undef U_8
#undef U_16
#undef U_32
#undef U_ptr
#undef a
#undef cmp
#undef v
#undef set
#undef U_a
#undef U_cmp
#undef U_v
#undef U_set
#undef make_atomic_add
#undef make_atomic_cas
#undef make_atomic_load
#undef make_atomic_store
#undef make_atomic_fas
#undef make_atomic_add_body
#undef make_atomic_cas_body
#undef make_atomic_load_body
#undef make_atomic_store_body
#undef make_atomic_fas_body
#undef intptr
/*
the macro below defines (as an expression) the code that
will be run in spin-loops. Intel manuals recummend to have PAUSE there.
It is expected to be defined in include/atomic/ *.h files
*/
#ifndef LF_BACKOFF
#define LF_BACKOFF (1)
#endif
#define MY_ATOMIC_OK 0
#define MY_ATOMIC_NOT_1CPU 1
extern int my_atomic_initialize();

View File

@ -14,7 +14,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* This file includes constants used with all databases */
/* Author: Michael Widenius */
#ifndef _my_base_h
#define _my_base_h
@ -48,10 +47,11 @@
#define HA_OPEN_FOR_REPAIR 32 /* open even if crashed */
#define HA_OPEN_FROM_SQL_LAYER 64
#define HA_OPEN_MMAP 128 /* open memory mapped */
#define HA_OPEN_COPY 256 /* Open copy (for repair) */
/* Internal temp table, used for temporary results */
#define HA_OPEN_INTERNAL_TABLE 256
#define HA_OPEN_INTERNAL_TABLE 512
/* The following is parameter to ha_rkey() how to use key */
/* The following is parameter to ha_rkey() how to use key */
/*
We define a complete-field prefix of a key value as a prefix where
@ -137,7 +137,7 @@ enum ha_extra_function {
HA_EXTRA_RESET_STATE, /* Reset positions */
HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/
HA_EXTRA_NO_IGNORE_DUP_KEY,
HA_EXTRA_PREPARE_FOR_DELETE,
HA_EXTRA_PREPARE_FOR_DROP,
HA_EXTRA_PREPARE_FOR_UPDATE, /* Remove read cache if problems */
HA_EXTRA_PRELOAD_BUFFER_SIZE, /* Set buffer size for preloading */
/*
@ -187,7 +187,9 @@ enum ha_extra_function {
Inform handler that an "INSERT...ON DUPLICATE KEY UPDATE" will be
executed. This condition is unset by HA_EXTRA_NO_IGNORE_DUP_KEY.
*/
HA_EXTRA_INSERT_WITH_UPDATE
HA_EXTRA_INSERT_WITH_UPDATE,
/* Inform handler that we will do a rename */
HA_EXTRA_PREPARE_FOR_RENAME
};
/* The following is parameter to ha_panic() */
@ -292,6 +294,7 @@ enum ha_base_keytype {
#define HA_OPTION_NO_PACK_KEYS 128 /* Reserved for MySQL */
#define HA_OPTION_CREATE_FROM_ENGINE 256
#define HA_OPTION_RELIES_ON_SQL_LAYER 512
#define HA_OPTION_NULL_FIELDS 1024
#define HA_OPTION_TEMP_COMPRESS_RECORD ((uint) 16384) /* set by isamchk */
#define HA_OPTION_READ_ONLY_DATA ((uint) 32768) /* Set by isamchk */
@ -474,7 +477,7 @@ enum en_fieldtype {
};
enum data_file_type {
STATIC_RECORD,DYNAMIC_RECORD,COMPRESSED_RECORD
STATIC_RECORD, DYNAMIC_RECORD, COMPRESSED_RECORD, BLOCK_RECORD
};
/* For key ranges */
@ -526,4 +529,7 @@ typedef ulong ha_rows;
#define HA_VARCHAR_PACKLENGTH(field_length) ((field_length) < 256 ? 1 :2)
/* invalidator function reference for Query Cache */
typedef void (* invalidator_by_filename)(const char * filename);
#endif /* _my_base_h */

107
include/my_bit.h Normal file
View File

@ -0,0 +1,107 @@
/*
Some useful bit functions
*/
#ifdef HAVE_INLINE
extern const char _my_bits_nbits[256];
extern const uchar _my_bits_reverse_table[256];
/*
Find smallest X in 2^X >= value
This can be used to divide a number with value by doing a shift instead
*/
STATIC_INLINE uint my_bit_log2(ulong value)
{
uint bit;
for (bit=0 ; value > 1 ; value>>=1, bit++) ;
return bit;
}
STATIC_INLINE uint my_count_bits(ulonglong v)
{
#if SIZEOF_LONG_LONG > 4
/* The following code is a bit faster on 16 bit machines than if we would
only shift v */
ulong v2=(ulong) (v >> 32);
return (uint) (uchar) (_my_bits_nbits[(uchar) v] +
_my_bits_nbits[(uchar) (v >> 8)] +
_my_bits_nbits[(uchar) (v >> 16)] +
_my_bits_nbits[(uchar) (v >> 24)] +
_my_bits_nbits[(uchar) (v2)] +
_my_bits_nbits[(uchar) (v2 >> 8)] +
_my_bits_nbits[(uchar) (v2 >> 16)] +
_my_bits_nbits[(uchar) (v2 >> 24)]);
#else
return (uint) (uchar) (_my_bits_nbits[(uchar) v] +
_my_bits_nbits[(uchar) (v >> 8)] +
_my_bits_nbits[(uchar) (v >> 16)] +
_my_bits_nbits[(uchar) (v >> 24)]);
#endif
}
STATIC_INLINE uint my_count_bits_ushort(ushort v)
{
return _my_bits_nbits[v];
}
/*
Next highest power of two
SYNOPSIS
my_round_up_to_next_power()
v Value to check
RETURN
Next or equal power of 2
Note: 0 will return 0
NOTES
Algorithm by Sean Anderson, according to:
http://graphics.stanford.edu/~seander/bithacks.html
(Orignal code public domain)
Comments shows how this works with 01100000000000000000000000001011
*/
STATIC_INLINE uint32 my_round_up_to_next_power(uint32 v)
{
v--; /* 01100000000000000000000000001010 */
v|= v >> 1; /* 01110000000000000000000000001111 */
v|= v >> 2; /* 01111100000000000000000000001111 */
v|= v >> 4; /* 01111111110000000000000000001111 */
v|= v >> 8; /* 01111111111111111100000000001111 */
v|= v >> 16; /* 01111111111111111111111111111111 */
return v+1; /* 10000000000000000000000000000000 */
}
STATIC_INLINE uint32 my_clear_highest_bit(uint32 v)
{
uint32 w=v >> 1;
w|= w >> 1;
w|= w >> 2;
w|= w >> 4;
w|= w >> 8;
w|= w >> 16;
return v & w;
}
STATIC_INLINE uint32 my_reverse_bits(uint32 key)
{
return
(_my_bits_reverse_table[ key & 255] << 24) |
(_my_bits_reverse_table[(key>> 8) & 255] << 16) |
(_my_bits_reverse_table[(key>>16) & 255] << 8) |
_my_bits_reverse_table[(key>>24) ];
}
#else
extern uint my_bit_log2(ulong value);
extern uint32 my_round_up_to_next_power(uint32 v);
uint32 my_clear_highest_bit(uint32 v);
uint32 my_reverse_bits(uint32 key);
extern uint my_count_bits(ulonglong v);
extern uint my_count_bits_ushort(ushort v);
#endif

View File

@ -101,7 +101,7 @@ extern FILE *_db_fp_(void);
#define DBUG_LONGJMP(a1) longjmp(a1)
#define DBUG_DUMP(keyword,a1,a2)
#define DBUG_END()
#define DBUG_ASSERT(A)
#define DBUG_ASSERT(A) do { } while(0)
#define DBUG_LOCK_FILE
#define DBUG_FILE (stderr)
#define DBUG_UNLOCK_FILE

View File

@ -88,6 +88,13 @@
#endif
#endif /* _WIN32... */
/*
STACK_DIRECTION was removed from 5.1 and then that was merged into Maria;
then it was added back into 5.1 but not yet merged into Maria.
When merge done, remove this.
*/
#define STACK_DIRECTION -1
/* Make it easier to add conditionl code for windows */
#ifdef __WIN__
#define IF_WIN(A,B) (A)
@ -242,6 +249,8 @@
#endif
#undef inline_test_2
#undef inline_test_1
/* helper macro for "instantiating" inline functions */
#define STATIC_INLINE static inline
/*
The following macros are used to control inlining a bit more than
@ -1015,6 +1024,8 @@ typedef long long intptr;
#error sizeof(void *) is neither sizeof(int) nor sizeof(long) nor sizeof(long long)
#endif
#define MY_ERRPTR ((void*)(intptr)1)
#ifdef USE_RAID
/*
The following is done with a if to not get problems with pre-processors
@ -1476,6 +1487,7 @@ do { doubleget_union _tmp; \
#define dlerror() ""
#endif
#ifndef __NETWARE__
/*
* Include standard definitions of operator new and delete.
@ -1506,6 +1518,13 @@ inline void operator delete[](void*, void*) { /* Do nothing */ }
#if !defined(max)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
/*
Only Linux is known to need an explicit sync of the directory to make sure a
file creation/deletion/renaming in(from,to) this directory durable.
*/
#ifdef TARGET_OS_LINUX
#define NEED_EXPLICIT_SYNC_DIR 1
#endif
#endif /* my_global_h */

View File

@ -18,10 +18,30 @@
#ifndef _my_handler_h
#define _my_handler_h
#include "my_base.h"
#include "m_ctype.h"
#include "myisampack.h"
/*
There is a hard limit for the maximum number of keys as there are only
8 bits in the index file header for the number of keys in a table.
This means that 0..255 keys can exist for a table. The idea of
HA_MAX_POSSIBLE_KEY is to ensure that one can use myisamchk & tools on
a MyISAM table for which one has more keys than MyISAM is normally
compiled for. If you don't have this, you will get a core dump when
running myisamchk compiled for 128 keys on a table with 255 keys.
*/
#define HA_MAX_POSSIBLE_KEY 255 /* For myisamchk */
/*
The following defines can be increased if necessary.
But beware the dependency of HA_MAX_POSSIBLE_KEY_BUFF and HA_MAX_KEY_LENGTH.
*/
#define HA_MAX_KEY_LENGTH 1000 /* Max length in bytes */
#define HA_MAX_KEY_SEG 16 /* Max segments for key */
#define HA_MAX_POSSIBLE_KEY_BUFF (HA_MAX_KEY_LENGTH + 24+ 6+6)
#define HA_MAX_KEY_BUFF (HA_MAX_KEY_LENGTH+HA_MAX_KEY_SEG*6+8+8)
typedef struct st_HA_KEYSEG /* Key-portion */
{
CHARSET_INFO *charset;
@ -38,33 +58,35 @@ typedef struct st_HA_KEYSEG /* Key-portion */
} HA_KEYSEG;
#define get_key_length(length,key) \
{ if ((uchar) *(key) != 255) \
length= (uint) (uchar) *((key)++); \
{ if (*(uchar*) (key) != 255) \
length= (uint) *(uchar*) ((key)++); \
else \
{ length=mi_uint2korr((key)+1); (key)+=3; } \
{ length= mi_uint2korr((key)+1); (key)+=3; } \
}
#define get_key_length_rdonly(length,key) \
{ if ((uchar) *(key) != 255) \
length= ((uint) (uchar) *((key))); \
{ if (*(uchar*) (key) != 255) \
length= ((uint) *(uchar*) ((key))); \
else \
{ length=mi_uint2korr((key)+1); } \
{ length= mi_uint2korr((key)+1); } \
}
#define get_key_pack_length(length,length_pack,key) \
{ if ((uchar) *(key) != 255) \
{ length= (uint) (uchar) *((key)++); length_pack=1; }\
{ if (*(uchar*) (key) != 255) \
{ length= (uint) *(uchar*) ((key)++); length_pack= 1; }\
else \
{ length=mi_uint2korr((key)+1); (key)+=3; length_pack=3; } \
{ length=mi_uint2korr((key)+1); (key)+= 3; length_pack= 3; } \
}
#define store_key_length_inc(key,length) \
{ if ((length) < 255) \
{ *(key)++=(length); } \
{ *(key)++= (length); } \
else \
{ *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \
}
#define size_to_store_key_length(length) ((length) < 255 ? 1 : 3)
#define get_rec_bits(bit_ptr, bit_ofs, bit_len) \
(((((uint16) (bit_ptr)[1] << 8) | (uint16) (bit_ptr)[0]) >> (bit_ofs)) & \
((1 << (bit_len)) - 1))
@ -81,12 +103,20 @@ typedef struct st_HA_KEYSEG /* Key-portion */
#define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \
set_rec_bits(0, bit_ptr, bit_ofs, bit_len)
extern int mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
extern int ha_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
my_bool, my_bool);
extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
register uchar *b, uint key_length, uint nextflag,
uint *diff_pos);
extern HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a);
extern void my_handler_error_register(void);
extern void my_handler_error_unregister(void);
/*
Inside an in-memory data record, memory pointers to pieces of the
record (like BLOBs) are stored in their native byte order and in
this amount of bytes.
*/
#define portable_sizeof_char_ptr 8
#endif /* _my_handler_h */

View File

@ -51,6 +51,7 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_WME 16 /* Write message on error */
#define MY_WAIT_IF_FULL 32 /* Wait and try again if disk full error */
#define MY_IGNORE_BADFD 32 /* my_sync: ignore 'bad descriptor' errors */
#define MY_SYNC_DIR 1024 /* my_create/delete/rename: sync directory */
#define MY_RAID 64 /* Support for RAID */
#define MY_FULL_IO 512 /* For my_read - loop intil I/O is complete */
#define MY_DONT_CHECK_FILESIZE 128 /* Option to init_io_cache() */
@ -212,6 +213,7 @@ extern int (*error_handler_hook)(uint my_err, const char *str,myf MyFlags);
extern int (*fatal_error_handler_hook)(uint my_err, const char *str,
myf MyFlags);
extern uint my_file_limit;
extern ulong my_thread_stack_size;
#ifdef HAVE_LARGE_PAGES
extern my_bool my_use_large_pages;
@ -276,7 +278,12 @@ enum cache_type
enum flush_type
{
FLUSH_KEEP, FLUSH_RELEASE, FLUSH_IGNORE_CHANGED, FLUSH_FORCE_WRITE
FLUSH_KEEP, /* flush block and keep it in the cache */
FLUSH_RELEASE, /* flush block and remove it from the cache */
FLUSH_IGNORE_CHANGED, /* remove block from the cache */
/* as my_disable_flush_pagecache_blocks is always 0, it is
strictly equivalent to FLUSH_KEEP */
FLUSH_FORCE_WRITE
};
typedef struct st_record_cache /* Used when cacheing records */
@ -627,6 +634,8 @@ extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags);
extern int my_fclose(FILE *fd,myf MyFlags);
extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags);
extern int my_sync(File fd, myf my_flags);
extern int my_sync_dir(const char *dir_name, myf my_flags);
extern int my_sync_dir_by_file(const char *file_name, myf my_flags);
extern int my_error _VARARGS((int nr,myf MyFlags, ...));
extern int my_printf_error _VARARGS((uint my_err, const char *format,
myf MyFlags, ...))
@ -661,7 +670,7 @@ extern char *my_tmpdir(MY_TMPDIR *tmpdir);
extern void free_tmpdir(MY_TMPDIR *tmpdir);
extern void my_remember_signal(int signal_number,sig_handler (*func)(int));
extern size_t dirname_part(char * to, const char *name, size_t *to_res_length);
extern size_t dirname_part(char * to,const char *name, size_t *to_res_length);
extern size_t dirname_length(const char *name);
#define base_name(A) (A+dirname_length(A))
extern int test_if_hard_path(const char *dir_name);
@ -707,7 +716,7 @@ extern sig_handler sigtstp_handler(int signal_number);
extern void handle_recived_signals(void);
extern sig_handler my_set_alarm_variable(int signo);
extern void my_string_ptr_sort(uchar *base, uint items, size_t size);
extern void my_string_ptr_sort(uchar *base,uint items,size_t size);
extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements,
size_t size_of_element,uchar *buffer[]);
extern qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size,
@ -773,6 +782,7 @@ extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,uchar * element);
extern uchar *alloc_dynamic(DYNAMIC_ARRAY *array);
extern uchar *pop_dynamic(DYNAMIC_ARRAY*);
extern my_bool set_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index);
extern my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements);
extern void get_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index);
extern void delete_dynamic(DYNAMIC_ARRAY *array);
extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index);
@ -839,11 +849,8 @@ extern int unpackfrm(uchar **, size_t *, const uchar *);
extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem,
size_t count);
extern uint my_bit_log2(ulong value);
extern uint32 my_round_up_to_next_power(uint32 v);
extern uint my_count_bits(ulonglong v);
extern uint my_count_bits_ushort(ushort v);
extern void my_sleep(ulong m_seconds);
extern ulong crc32(ulong crc, const uchar *buf, uint len);
extern uint my_set_max_open_files(uint files);
void my_free_open_file_info(void);
@ -861,7 +868,7 @@ extern int my_getncpus();
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0
#endif
#ifndef MAP_NORESERVE
#ifndef MAP_NORESERVE
#define MAP_NORESERVE 0 /* For irix and AIX */
#endif

View File

@ -31,33 +31,19 @@ extern "C" {
#include "keycache.h"
#endif
#include "my_handler.h"
#include <myisamchk.h>
#include <mysql/plugin.h>
/*
There is a hard limit for the maximum number of keys as there are only
8 bits in the index file header for the number of keys in a table.
This means that 0..255 keys can exist for a table. The idea of
MI_MAX_POSSIBLE_KEY is to ensure that one can use myisamchk & tools on
a MyISAM table for which one has more keys than MyISAM is normally
compiled for. If you don't have this, you will get a core dump when
running myisamchk compiled for 128 keys on a table with 255 keys.
Limit max keys according to HA_MAX_POSSIBLE_KEY; See myisamchk.h for details
*/
#define MI_MAX_POSSIBLE_KEY 255 /* For myisam_chk */
#if MAX_INDEXES > MI_MAX_POSSIBLE_KEY
#define MI_MAX_KEY MI_MAX_POSSIBLE_KEY /* Max allowed keys */
#if MAX_INDEXES > HA_MAX_POSSIBLE_KEY
#define MI_MAX_KEY HA_MAX_POSSIBLE_KEY /* Max allowed keys */
#else
#define MI_MAX_KEY MAX_INDEXES /* Max allowed keys */
#endif
#define MI_MAX_POSSIBLE_KEY_BUFF (1024+6+6) /* For myisam_chk */
/*
The following defines can be increased if necessary.
But beware the dependency of MI_MAX_POSSIBLE_KEY_BUFF and MI_MAX_KEY_LENGTH.
*/
#define MI_MAX_KEY_LENGTH 1000 /* Max length in bytes */
#define MI_MAX_KEY_SEG 16 /* Max segments for key */
#define MI_MAX_KEY_BUFF (MI_MAX_KEY_LENGTH+MI_MAX_KEY_SEG*6+8+8)
#define MI_MAX_MSG_BUF 1024 /* used in CHECK TABLE, REPAIR TABLE */
#define MI_NAME_IEXT ".MYI"
#define MI_NAME_DEXT ".MYD"
@ -69,8 +55,6 @@ extern "C" {
#define MI_MIN_KEY_BLOCK_LENGTH 1024 /* Min key block length */
#define MI_MAX_KEY_BLOCK_LENGTH 16384
#define mi_portable_sizeof_char_ptr 8
/*
In the following macros '_keyno_' is 0 .. keys-1.
If there can be more keys than bits in the key_map, the highest bit
@ -256,9 +240,6 @@ typedef struct st_columndef /* column information */
#endif
} MI_COLUMNDEF;
/* invalidator function reference for Query Cache */
typedef void (* invalidator_by_filename)(const char * filename);
extern char * myisam_log_filename; /* Name of logfile */
extern ulong myisam_block_size;
extern ulong myisam_concurrent_insert;
@ -302,7 +283,7 @@ extern int mi_extra(struct st_myisam_info *file,
enum ha_extra_function function,
void *extra_arg);
extern int mi_reset(struct st_myisam_info *file);
extern ha_rows mi_records_in_range(MI_INFO *info, int inx,
extern ha_rows mi_records_in_range(MI_INFO *info,int inx,
key_range *min_key, key_range *max_key);
extern int mi_log(int activate_log);
extern int mi_is_changed(struct st_myisam_info *info);
@ -310,195 +291,117 @@ extern int mi_delete_all_rows(struct st_myisam_info *info);
extern ulong _mi_calc_blob_length(uint length , const uchar *pos);
extern uint mi_get_pointer_length(ulonglong file_length, uint def);
/* this is used to pass to mysql_myisamchk_table -- by Sasha Pachev */
/* this is used to pass to mysql_myisamchk_table */
#define MYISAMCHK_REPAIR 1 /* equivalent to myisamchk -r */
#define MYISAMCHK_VERIFY 2 /* Verify, run repair if failure */
/*
Definitions needed for myisamchk.c
typedef uint mi_bit_type;
Entries marked as "QQ to be removed" are NOT used to
pass check/repair options to mi_check.c. They are used
internally by myisamchk.c or/and ha_myisam.cc and should NOT
be stored together with other flags. They should be removed
from the following list to make addition of new flags possible.
*/
typedef struct st_mi_bit_buff
{ /* Used for packing of record */
mi_bit_type current_byte;
uint bits;
uchar *pos, *end, *blob_pos, *blob_end;
uint error;
} MI_BIT_BUFF;
#define T_AUTO_INC 1
#define T_AUTO_REPAIR 2 /* QQ to be removed */
#define T_BACKUP_DATA 4
#define T_CALC_CHECKSUM 8
#define T_CHECK 16 /* QQ to be removed */
#define T_CHECK_ONLY_CHANGED 32 /* QQ to be removed */
#define T_CREATE_MISSING_KEYS 64
#define T_DESCRIPT 128
#define T_DONT_CHECK_CHECKSUM 256
#define T_EXTEND 512
#define T_FAST (1L << 10) /* QQ to be removed */
#define T_FORCE_CREATE (1L << 11) /* QQ to be removed */
#define T_FORCE_UNIQUENESS (1L << 12)
#define T_INFO (1L << 13)
#define T_MEDIUM (1L << 14)
#define T_QUICK (1L << 15) /* QQ to be removed */
#define T_READONLY (1L << 16) /* QQ to be removed */
#define T_REP (1L << 17)
#define T_REP_BY_SORT (1L << 18) /* QQ to be removed */
#define T_REP_PARALLEL (1L << 19) /* QQ to be removed */
#define T_RETRY_WITHOUT_QUICK (1L << 20)
#define T_SAFE_REPAIR (1L << 21)
#define T_SILENT (1L << 22)
#define T_SORT_INDEX (1L << 23) /* QQ to be removed */
#define T_SORT_RECORDS (1L << 24) /* QQ to be removed */
#define T_STATISTICS (1L << 25)
#define T_UNPACK (1L << 26)
#define T_UPDATE_STATE (1L << 27)
#define T_VERBOSE (1L << 28)
#define T_VERY_SILENT (1L << 29)
#define T_WAIT_FOREVER (1L << 30)
#define T_WRITE_LOOP ((ulong) 1L << 31)
#define T_REP_ANY (T_REP | T_REP_BY_SORT | T_REP_PARALLEL)
/*
Flags used by myisamchk.c or/and ha_myisam.cc that are NOT passed
to mi_check.c follows:
*/
#define TT_USEFRM 1
#define TT_FOR_UPGRADE 2
#define O_NEW_INDEX 1 /* Bits set in out_flag */
#define O_NEW_DATA 2
#define O_DATA_LOST 4
/* these struct is used by my_check to tell it what to do */
typedef struct st_sort_key_blocks /* Used when sorting */
typedef struct st_sort_info
{
uchar *buff,*end_pos;
uchar lastkey[MI_MAX_POSSIBLE_KEY_BUFF];
uint last_length;
int inited;
} SORT_KEY_BLOCKS;
/*
MyISAM supports several statistics collection methods. Currently statistics
collection method is not stored in MyISAM file and has to be specified for
each table analyze/repair operation in MI_CHECK::stats_method.
*/
typedef enum
{
/* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */
MI_STATS_METHOD_NULLS_NOT_EQUAL,
/* Treat NULLs as equal when collecting statistics (like 4.0 did) */
MI_STATS_METHOD_NULLS_EQUAL,
/* Ignore NULLs - count only tuples without NULLs in the index components */
MI_STATS_METHOD_IGNORE_NULLS
} enum_mi_stats_method;
typedef struct st_mi_check_param
{
ulonglong auto_increment_value;
ulonglong max_data_file_length;
ulonglong keys_in_use;
ulonglong max_record_length;
my_off_t search_after_block;
my_off_t new_file_pos,key_file_blocks;
my_off_t keydata,totaldata,key_blocks,start_check_pos;
ha_rows total_records,total_deleted;
ha_checksum record_checksum,glob_crc;
ulong use_buffers,read_buffer_length,write_buffer_length,
sort_buffer_length,sort_key_blocks;
uint out_flag,warning_printed,error_printed,verbose;
uint opt_sort_key,total_files,max_level;
uint testflag, key_cache_block_size;
uint8 language;
my_bool using_global_keycache, opt_lock_memory, opt_follow_links;
my_bool retry_repair, force_sort;
char temp_filename[FN_REFLEN],*isam_file_name;
MY_TMPDIR *tmpdir;
int tmpfile_createflag;
#ifdef THREAD
/* sync things */
pthread_mutex_t mutex;
pthread_cond_t cond;
#endif
MI_INFO *info;
HA_CHECK *param;
uchar *buff;
SORT_KEY_BLOCKS *key_block, *key_block_end;
SORT_FT_BUF *ft_buf;
my_off_t filelength, dupp, buff_length;
ha_rows max_records;
uint current_key, total_keys;
uint got_error, threads_running;
myf myf_rw;
IO_CACHE read_cache;
enum data_file_type new_data_file_type;
} MI_SORT_INFO;
typedef struct st_mi_sort_param
{
pthread_t thr;
IO_CACHE read_cache, tempfile, tempfile_for_exceptions;
DYNAMIC_ARRAY buffpek;
MI_BIT_BUFF bit_buff; /* For parallel repair of packrec. */
MI_KEYDEF *keyinfo;
MI_SORT_INFO *sort_info;
HA_KEYSEG *seg;
uchar **sort_keys;
uchar *rec_buff;
void *wordlist, *wordptr;
MEM_ROOT wordroot;
char *record;
MY_TMPDIR *tmpdir;
/*
The next two are used to collect statistics, see update_key_parts for
description.
*/
ulonglong unique_count[MI_MAX_KEY_SEG+1];
ulonglong notnull_count[MI_MAX_KEY_SEG+1];
ha_checksum key_crc[MI_MAX_POSSIBLE_KEY];
ulong rec_per_key_part[MI_MAX_KEY_SEG*MI_MAX_POSSIBLE_KEY];
void *thd;
const char *db_name, *table_name;
const char *op_name;
enum_mi_stats_method stats_method;
} MI_CHECK;
ulonglong unique[HA_MAX_KEY_SEG+1];
ulonglong notnull[HA_MAX_KEY_SEG+1];
typedef struct st_sort_ft_buf
{
uchar *buf, *end;
int count;
uchar lastkey[MI_MAX_KEY_BUFF];
} SORT_FT_BUF;
my_off_t pos,max_pos,filepos,start_recpos;
uint key, key_length,real_key_length,sortbuff_size;
uint maxbuffers, keys, find_length, sort_keys_length;
my_bool fix_datafile, master;
my_bool calc_checksum; /* calculate table checksum */
int (*key_cmp)(struct st_mi_sort_param *, const void *, const void *);
int (*key_read)(struct st_mi_sort_param *,void *);
int (*key_write)(struct st_mi_sort_param *, const void *);
void (*lock_in_memory)(HA_CHECK *);
NEAR int (*write_keys)(struct st_mi_sort_param *, register uchar **,
uint , struct st_buffpek *, IO_CACHE *);
NEAR uint (*read_to_buffer)(IO_CACHE *,struct st_buffpek *, uint);
NEAR int (*write_key)(struct st_mi_sort_param *, IO_CACHE *,uchar *,
uint, uint);
} MI_SORT_PARAM;
typedef struct st_sort_info
{
my_off_t filelength,dupp,buff_length;
ha_rows max_records;
uint current_key, total_keys;
myf myf_rw;
enum data_file_type new_data_file_type;
MI_INFO *info;
MI_CHECK *param;
uchar *buff;
SORT_KEY_BLOCKS *key_block,*key_block_end;
SORT_FT_BUF *ft_buf;
/* sync things */
uint got_error, threads_running;
#ifdef THREAD
pthread_mutex_t mutex;
pthread_cond_t cond;
#endif
} SORT_INFO;
/* functions in mi_check */
void myisamchk_init(MI_CHECK *param);
int chk_status(MI_CHECK *param, MI_INFO *info);
int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag);
int chk_size(MI_CHECK *param, MI_INFO *info);
int chk_key(MI_CHECK *param, MI_INFO *info);
int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend);
int mi_repair(MI_CHECK *param, register MI_INFO *info,
void myisamchk_init(HA_CHECK *param);
int chk_status(HA_CHECK *param, MI_INFO *info);
int chk_del(HA_CHECK *param, register MI_INFO *info, uint test_flag);
int chk_size(HA_CHECK *param, MI_INFO *info);
int chk_key(HA_CHECK *param, MI_INFO *info);
int chk_data_link(HA_CHECK *param, MI_INFO *info,int extend);
int mi_repair(HA_CHECK *param, register MI_INFO *info,
char * name, int rep_quick);
int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name);
int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
int mi_sort_index(HA_CHECK *param, register MI_INFO *info, char * name);
int mi_repair_by_sort(HA_CHECK *param, register MI_INFO *info,
const char * name, int rep_quick);
int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
int mi_repair_parallel(HA_CHECK *param, register MI_INFO *info,
const char * name, int rep_quick);
int change_to_newfile(const char * filename, const char * old_ext,
const char * new_ext, uint raid_chunks,
myf myflags);
int lock_file(MI_CHECK *param, File file, my_off_t start, int lock_type,
int lock_file(HA_CHECK *param, File file, my_off_t start, int lock_type,
const char *filetype, const char *filename);
void lock_memory(MI_CHECK *param);
void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
void lock_memory(HA_CHECK *param);
void update_auto_increment_key(HA_CHECK *param, MI_INFO *info,
my_bool repair);
int update_state_info(MI_CHECK *param, MI_INFO *info,uint update);
int update_state_info(HA_CHECK *param, MI_INFO *info,uint update);
void update_key_parts(MI_KEYDEF *keyinfo, ulong *rec_per_key_part,
ulonglong *unique, ulonglong *notnull,
ulonglong records);
int filecopy(MI_CHECK *param, File to,File from,my_off_t start,
int filecopy(HA_CHECK *param, File to,File from,my_off_t start,
my_off_t length, const char *type);
int movepoint(MI_INFO *info,uchar *record,my_off_t oldpos,
my_off_t newpos, uint prot_key);
int write_data_suffix(SORT_INFO *sort_info, my_bool fix_datafile);
int write_data_suffix(MI_SORT_INFO *sort_info, my_bool fix_datafile);
int test_if_almost_full(MI_INFO *info);
int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename);
int recreate_table(HA_CHECK *param, MI_INFO **org_info, char *filename);
void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, ulonglong key_map,
my_bool force);
@ -512,6 +415,13 @@ void mi_change_key_cache(KEY_CACHE *old_key_cache,
KEY_CACHE *new_key_cache);
int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves);
int write_data_suffix(MI_SORT_INFO *sort_info, my_bool fix_datafile);
int flush_pending_blocks(MI_SORT_PARAM *param);
int sort_ft_buf_flush(MI_SORT_PARAM *sort_param);
int thr_write_keys(MI_SORT_PARAM *sort_param);
int sort_write_record(MI_SORT_PARAM *sort_param);
int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ulong);
#ifdef __cplusplus
}
#endif

164
include/myisamchk.h Normal file
View File

@ -0,0 +1,164 @@
/* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Definitions needed for myisamchk/mariachk.c */
/*
Entries marked as "QQ to be removed" are NOT used to
pass check/repair options to xxx_check.c. They are used
internally by xxxchk.c or/and ha_xxxx.cc and should NOT
be stored together with other flags. They should be removed
from the following list to make addition of new flags possible.
*/
#ifndef _myisamchk_h
#define _myisamchk_h
#define T_AUTO_INC 1
#define T_AUTO_REPAIR 2 /* QQ to be removed */
#define T_BACKUP_DATA 4
#define T_CALC_CHECKSUM 8
#define T_CHECK 16 /* QQ to be removed */
#define T_CHECK_ONLY_CHANGED 32 /* QQ to be removed */
#define T_CREATE_MISSING_KEYS 64
#define T_DESCRIPT 128
#define T_DONT_CHECK_CHECKSUM 256
#define T_EXTEND 512
#define T_FAST (1L << 10) /* QQ to be removed */
#define T_FORCE_CREATE (1L << 11) /* QQ to be removed */
#define T_FORCE_UNIQUENESS (1L << 12)
#define T_INFO (1L << 13)
#define T_MEDIUM (1L << 14)
#define T_QUICK (1L << 15) /* QQ to be removed */
#define T_READONLY (1L << 16) /* QQ to be removed */
#define T_REP (1L << 17)
#define T_REP_BY_SORT (1L << 18) /* QQ to be removed */
#define T_REP_PARALLEL (1L << 19) /* QQ to be removed */
#define T_RETRY_WITHOUT_QUICK (1L << 20)
#define T_SAFE_REPAIR (1L << 21)
#define T_SILENT (1L << 22)
#define T_SORT_INDEX (1L << 23) /* QQ to be removed */
#define T_SORT_RECORDS (1L << 24) /* QQ to be removed */
#define T_STATISTICS (1L << 25)
#define T_UNPACK (1L << 26)
#define T_UPDATE_STATE (1L << 27)
#define T_VERBOSE (1L << 28)
#define T_VERY_SILENT (1L << 29)
#define T_WAIT_FOREVER (1L << 30)
#define T_WRITE_LOOP ((ulong) 1L << 31)
#define T_REP_ANY (T_REP | T_REP_BY_SORT | T_REP_PARALLEL)
/*
Flags used by xxxxchk.c or/and ha_xxxx.cc that are NOT passed
to xxxcheck.c follows:
*/
#define TT_USEFRM 1
#define TT_FOR_UPGRADE 2
#define O_NEW_INDEX 1 /* Bits set in out_flag */
#define O_NEW_DATA 2
#define O_DATA_LOST 4
typedef struct st_sort_key_blocks /* Used when sorting */
{
uchar *buff, *end_pos;
uchar lastkey[HA_MAX_POSSIBLE_KEY_BUFF];
uint last_length;
int inited;
} SORT_KEY_BLOCKS;
/*
MARIA/MYISAM supports several statistics collection
methods. Currently statistics collection method is not stored in
MARIA file and has to be specified for each table analyze/repair
operation in MI_CHECK::stats_method.
*/
typedef enum
{
/* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */
MI_STATS_METHOD_NULLS_NOT_EQUAL,
/* Treat NULLs as equal when collecting statistics (like 4.0 did) */
MI_STATS_METHOD_NULLS_EQUAL,
/* Ignore NULLs - count only tuples without NULLs in the index components */
MI_STATS_METHOD_IGNORE_NULLS
} enum_handler_stats_method;
typedef struct st_handler_check_param
{
char *isam_file_name;
MY_TMPDIR *tmpdir;
void *thd;
const char *db_name, *table_name, *op_name;
ulonglong auto_increment_value;
ulonglong max_data_file_length;
ulonglong keys_in_use;
ulonglong max_record_length;
/*
The next two are used to collect statistics, see update_key_parts for
description.
*/
ulonglong unique_count[HA_MAX_KEY_SEG + 1];
ulonglong notnull_count[HA_MAX_KEY_SEG + 1];
my_off_t search_after_block;
my_off_t new_file_pos, key_file_blocks;
my_off_t keydata, totaldata, key_blocks, start_check_pos;
my_off_t used, empty, splits, del_length, link_used;
ha_rows total_records, total_deleted, records,del_blocks;
ha_rows full_page_count, tail_count;
ha_checksum record_checksum, glob_crc;
ha_checksum key_crc[HA_MAX_POSSIBLE_KEY];
ha_checksum tmp_key_crc[HA_MAX_POSSIBLE_KEY];
ha_checksum tmp_record_checksum;
ulong use_buffers, read_buffer_length, write_buffer_length;
ulong sort_buffer_length, sort_key_blocks;
ulong rec_per_key_part[HA_MAX_KEY_SEG * HA_MAX_POSSIBLE_KEY];
uint out_flag, warning_printed, error_printed, verbose;
uint opt_sort_key, total_files, max_level;
uint testflag, key_cache_block_size, pagecache_block_size;
int tmpfile_createflag, err_count;
myf myf_rw;
uint8 language;
my_bool using_global_keycache, opt_lock_memory, opt_follow_links;
my_bool retry_repair, force_sort, calc_checksum, static_row_size;
char temp_filename[FN_REFLEN];
IO_CACHE read_cache;
enum_handler_stats_method stats_method;
} HA_CHECK;
typedef struct st_sort_ftbuf
{
uchar *buf, *end;
int count;
uchar lastkey[HA_MAX_KEY_BUFF];
} SORT_FT_BUF;
typedef struct st_buffpek {
my_off_t file_pos; /* Where we are in the sort file */
uchar *base, *key; /* Key pointers */
ha_rows count; /* Number of rows in table */
ulong mem_count; /* numbers of keys in memory */
ulong max_keys; /* Max keys in buffert */
} BUFFPEK;
#endif /* _myisamchk_h */

26
include/wqueue.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _wqueue_h
#define _wqueue_h
#include <my_global.h>
#include <my_pthread.h>
/* info about requests in a waiting queue */
typedef struct st_pagecache_wqueue
{
struct st_my_thread_var *last_thread; /* circular list of waiting
threads */
} WQUEUE;
#ifdef THREAD
void wqueue_link_into_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
void wqueue_unlink_from_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
void wqueue_add_to_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
void wqueue_add_and_wait(WQUEUE *wqueue,
struct st_my_thread_var *thread,
pthread_mutex_t *lock);
void wqueue_release_queue(WQUEUE *wqueue);
#endif
#endif

View File

@ -68,7 +68,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
mf_iocache2.lo my_seek.lo my_sleep.lo \
my_pread.lo mf_cache.lo md5.lo sha1.lo \
my_getopt.lo my_gethostbyname.lo my_port.lo \
my_rename.lo my_chsize.lo my_getsystime.lo
my_rename.lo my_chsize.lo my_sync.lo my_getsystime.lo
sqlobjects = net.lo
sql_cmn_objects = pack.lo client.lo my_time.lo

View File

@ -9,9 +9,9 @@
let $SERVER_VERSION=`select version()`;
create table t1 (a int);
create table t1 (a int) ENGINE=MyISAM;
insert into t1 values (10);
create table t2 (a int);
create table t2 (a int) ENGINE=MyISAM;
create table t3 (a int) engine=merge union(t1);
create table t4 (a int);
# We force the slave to open t3 (because we want to try confusing him) with this :

View File

@ -17,7 +17,7 @@ select @@global.binlog_format;
# happened only in statement-based binlogging.
#
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64)) ENGINE=MyISAM;
let $query = "INSERT DELAYED INTO t1 VALUES (null, 'Dr. No'), (null, 'From Russia With Love'), (null, 'Goldfinger'), (null, 'Thunderball'), (null, 'You Only Live Twice')";
--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=200 --query=$query --delimiter=";"

View File

@ -0,0 +1,4 @@
-- require r/have_maria.require
disable_query_log;
show variables like "have_maria";
enable_query_log;

View File

@ -52,7 +52,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
create table t5 as select
eval create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,

View File

@ -165,6 +165,7 @@ our $opt_small_bench= 0;
our $opt_big_test= 0;
our @opt_extra_mysqld_opt;
our @opt_extra_mysqltest_opt;
our $opt_compress;
our $opt_ssl;
@ -548,6 +549,9 @@ sub command_line_setup () {
# Extra options used when starting mysqld
'mysqld=s' => \@opt_extra_mysqld_opt,
# Extra options used when starting mysqld
'mysqltest=s' => \@opt_extra_mysqltest_opt,
# Run test on running server
'extern' => \$opt_extern,
'ndb-connectstring=s' => \$opt_ndbconnectstring,
@ -898,7 +902,7 @@ sub command_line_setup () {
# --------------------------------------------------------------------------
if ($opt_extern)
{
mtr_report("Disable instance manager when running with extern mysqld");
# mtr_report("Disable instance manager when running with extern mysqld");
$opt_skip_im= 1;
}
elsif ( $mysql_version_id < 50000 )
@ -1264,19 +1268,6 @@ sub command_line_setup () {
$path_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log";
$path_snapshot= "$opt_tmpdir/snapshot_$opt_master_myport/";
if ( $opt_valgrind and $opt_debug )
{
# When both --valgrind and --debug is selected, send
# all output to the trace file, making it possible to
# see the exact location where valgrind complains
foreach my $mysqld (@{$master}, @{$slave})
{
my $sidx= $mysqld->{idx} ? "$mysqld->{idx}" : "";
$mysqld->{path_myerr}=
"$opt_vardir/log/" . $mysqld->{type} . "$sidx.trace";
}
}
}
#
@ -2056,7 +2047,10 @@ sub environment_setup () {
$ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables;
}
$ENV{'MYSQL_FIX_PRIVILEGE_TABLES'}= $file_mysql_fix_privilege_tables;
if ( !$opt_extern )
{
$ENV{'MYSQL_FIX_PRIVILEGE_TABLES'}= $file_mysql_fix_privilege_tables;
}
# ----------------------------------------------------
# Setup env so childs can execute my_print_defaults
@ -2340,6 +2334,25 @@ sub setup_vardir() {
{
unlink($name);
}
if ( $opt_valgrind and $opt_debug )
{
# When both --valgrind and --debug is selected, send
# all output to the trace file, making it possible to
# see the exact location where valgrind complains
foreach my $mysqld (@{$master}, @{$slave})
{
my $sidx= $mysqld->{idx} ? "$mysqld->{idx}" : "";
my $trace_name= "$opt_vardir/log/" . $mysqld->{type} . "$sidx.trace";
open(LOG, ">$mysqld->{path_myerr}") or die "Can't create $mysqld->{path_myerr}\n";
print LOG "
NOTE: When running with --valgrind --debug the output from the .err file is
stored together with the trace file to make it easier to find the exact
position for valgrind errors.
See trace file $trace_name.\n";
close(LOG);
$mysqld->{path_myerr}= $trace_name;
}
}
}
@ -4750,6 +4763,11 @@ sub run_mysqltest ($) {
mtr_add_arg($args, "--skip-ssl");
}
foreach my $arg ( @opt_extra_mysqltest_opt )
{
mtr_add_arg($args, "%s", $arg);
}
# ----------------------------------------------------------------------
# If embedded server, we create server args to give mysqltest to pass on
# ----------------------------------------------------------------------

View File

@ -298,7 +298,7 @@ t1 0 a 1 a A 3 NULL NULL YES BTREE
t1 0 a 2 b A 300 NULL NULL YES BTREE
t1 1 b 1 b A 100 NULL NULL YES BTREE
drop table t1;
CREATE TABLE t1 (i int(10), index(i) );
CREATE TABLE t1 (i int(10), index(i) ) ENGINE=MyISAM;
ALTER TABLE t1 DISABLE KEYS;
INSERT DELAYED INTO t1 VALUES(1),(2),(3);
ALTER TABLE t1 ENABLE KEYS;

View File

@ -0,0 +1,2 @@
Variable_name Value
have_maria YES

View File

@ -0,0 +1,61 @@
set storage_engine=maria;
affected rows: 0
drop table if exists t1, t2;
affected rows: 0
create table t1(a char(3));
affected rows: 0
insert into t1 values("abc");
affected rows: 1
insert into t1 select "def" from t1;
affected rows: 1
info: Records: 1 Duplicates: 0 Warnings: 0
insert into t1 select "ghi" from t1;
affected rows: 2
info: Records: 2 Duplicates: 0 Warnings: 0
insert into t1 select "jkl" from t1;
affected rows: 4
info: Records: 4 Duplicates: 0 Warnings: 0
insert into t1 select "mno" from t1;
affected rows: 8
info: Records: 8 Duplicates: 0 Warnings: 0
insert into t1 select "pqr" from t1;
affected rows: 16
info: Records: 16 Duplicates: 0 Warnings: 0
insert into t1 select "stu" from t1;
affected rows: 32
info: Records: 32 Duplicates: 0 Warnings: 0
insert into t1 select "vwx" from t1;
affected rows: 64
info: Records: 64 Duplicates: 0 Warnings: 0
insert into t1 select "yza" from t1;
affected rows: 128
info: Records: 128 Duplicates: 0 Warnings: 0
insert into t1 select "ceg" from t1;
affected rows: 256
info: Records: 256 Duplicates: 0 Warnings: 0
insert into t1 select "ikm" from t1;
affected rows: 512
info: Records: 512 Duplicates: 0 Warnings: 0
insert into t1 select "oqs" from t1;
affected rows: 1024
info: Records: 1024 Duplicates: 0 Warnings: 0
select count(*) from t1;
count(*)
2048
affected rows: 1
insert into t1 select "uwy" from t1;
affected rows: 2048
info: Records: 2048 Duplicates: 0 Warnings: 0
create table t2 select * from t1;
affected rows: 4096
info: Records: 4096 Duplicates: 0 Warnings: 0
select count(*) from t1;
count(*)
4096
affected rows: 1
select count(*) from t2;
count(*)
4096
affected rows: 1
drop table t1, t2;
affected rows: 0

View File

@ -0,0 +1,23 @@
set global storage_engine=maria;
set session storage_engine=maria;
drop table if exists t1;
SET SQL_WARNINGS=1;
RESET MASTER;
set binlog_format=statement;
CREATE TABLE t1 (a int primary key);
insert t1 values (1),(2),(3);
insert t1 values (4),(2),(5);
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
select * from t1;
a
1
2
3
4
SHOW BINLOG EVENTS FROM 106;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 106 Query 1 204 use `test`; CREATE TABLE t1 (a int primary key)
master-bin.000001 204 Query 1 295 use `test`; insert t1 values (1),(2),(3)
master-bin.000001 295 Query 1 386 use `test`; insert t1 values (4),(2),(5)
drop table t1;
set binlog_format=default;

1975
mysql-test/r/maria.result Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
set global storage_engine=myisam;
set session storage_engine=myisam;
drop table if exists t1,t2,t3,t4,t5,t6;
drop database if exists mysqltest;
create table t1 (a int not null primary key auto_increment, message char(20));

View File

@ -723,7 +723,7 @@ DROP TABLE t1;
#
# Test for --insert-ignore
#
CREATE TABLE t1 (a int);
CREATE TABLE t1 (a int) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1),(2),(3);
INSERT INTO t1 VALUES (4),(5),(6);
@ -3644,8 +3644,8 @@ CREATE TABLE t1(a int);
INSERT INTO t1 VALUES (1), (2);
mysqldump: Input filename too long: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
DROP TABLE t1;
CREATE TABLE t2 (a int);
CREATE TABLE t3 (a int);
CREATE TABLE t2 (a int) ENGINE=MyISAM;
CREATE TABLE t3 (a int) ENGINE=MyISAM;
CREATE TABLE t1 (a int) ENGINE=merge UNION=(t2, t3);
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

View File

@ -1756,7 +1756,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
create table t5 as select
create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,

View File

@ -1739,7 +1739,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
create table t5 as select
create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,

View File

@ -1740,7 +1740,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
create table t5 as select
create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,

View File

@ -1676,7 +1676,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
create table t5 as select
create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,
@ -4697,7 +4697,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
create table t5 as select
create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,

3144
mysql-test/r/ps_maria.result Normal file

File diff suppressed because it is too large Load Diff

View File

@ -42,9 +42,9 @@ drop table t1;
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
create table t1 (a int not null);
create table t1 (a int not null) ENGINE=MyISAM;
insert into t1 values (1),(2),(3);
create table t2 (a int not null);
create table t2 (a int not null) ENGINE=MyISAM;
insert into t2 values (4),(5),(6);
create table t3 (a int not null) engine=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
select * from t3;
@ -460,7 +460,7 @@ Qcache_queries_in_cache 2
drop table t1;
flush query cache;
reset query cache;
create table t1 (a int not null);
create table t1 (a int not null) ENGINE=MyISAM;
insert into t1 values (1),(2),(3);
select * from t1;
a

View File

@ -627,8 +627,8 @@ a b
33 10
22 11
drop table t11, t12, t2;
CREATE TABLE t1 (x int);
create table t2 (a int);
CREATE TABLE t1 (x int) ENGINE=MyISAM;
create table t2 (a int) ENGINE=MyISAM;
create table t3 (b int);
insert into t2 values (1);
insert into t3 values (1),(2);
@ -675,7 +675,7 @@ x
11
2
drop table t1, t2, t3;
CREATE TABLE t1 (x int not null, y int, primary key (x));
CREATE TABLE t1 (x int not null, y int, primary key (x)) ENGINE=MyISAM;
create table t2 (a int);
create table t3 (a int);
insert into t2 values (1);

View File

@ -1739,7 +1739,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
create table t5 as select
create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,

View File

@ -9,7 +9,7 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
CREATE SCHEMA IF NOT EXISTS mysqlslap;
USE mysqlslap;
CREATE TABLE t1 (id INT, name VARCHAR(64));
CREATE TABLE t1 (id INT, name VARCHAR(64)) ENGINE=MyISAM;
SELECT COUNT(*) FROM mysqlslap.t1;
COUNT(*)
5000

View File

@ -4,21 +4,21 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
create table t1 (a int);
create table t1 (a int) ENGINE=MyISAM;
insert into t1 values (10);
create table t2 (a int);
create table t2 (a int) ENGINE=MyISAM;
create table t3 (a int) engine=merge union(t1);
create table t4 (a int);
insert into t4 select * from t3;
rename table t1 to t5, t2 to t1;
flush no_write_to_binlog tables;
SHOW BINLOG EVENTS FROM 623 ;
SHOW BINLOG EVENTS FROM 647 ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
select * from t3;
a
flush tables;
SHOW BINLOG EVENTS FROM 623 ;
SHOW BINLOG EVENTS FROM 647 ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
master-bin.000001 # Query 1 # use `test`; flush tables

View File

@ -11,7 +11,7 @@ USE mysqlslap;
select @@global.binlog_format;
@@global.binlog_format
ROW
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64)) ENGINE=MyISAM;
FLUSH TABLE t1;
SELECT COUNT(*) FROM t1;
COUNT(*)

View File

@ -4,21 +4,21 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
create table t1 (a int);
create table t1 (a int) ENGINE=MyISAM;
insert into t1 values (10);
create table t2 (a int);
create table t2 (a int) ENGINE=MyISAM;
create table t3 (a int) engine=merge union(t1);
create table t4 (a int);
insert into t4 select * from t3;
rename table t1 to t5, t2 to t1;
flush no_write_to_binlog tables;
SHOW BINLOG EVENTS FROM 656 ;
SHOW BINLOG EVENTS FROM 684 ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
select * from t3;
a
flush tables;
SHOW BINLOG EVENTS FROM 656 ;
SHOW BINLOG EVENTS FROM 684 ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
master-bin.000001 # Query 1 # use `test`; flush tables

View File

@ -11,7 +11,7 @@ USE mysqlslap;
select @@global.binlog_format;
@@global.binlog_format
STATEMENT
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64)) ENGINE=MyISAM;
FLUSH TABLE t1;
SELECT COUNT(*) FROM t1;
COUNT(*)
@ -77,7 +77,7 @@ USE mysqlslap;
select @@global.binlog_format;
@@global.binlog_format
MIXED
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64)) ENGINE=MyISAM;
FLUSH TABLE t1;
SELECT COUNT(*) FROM t1;
COUNT(*)

View File

@ -135,7 +135,7 @@ execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values(concat("for_23_",UUID()));
insert into t1 select "yesterday_24_";
create table t2 select rpad(UUID(),100,' ');
create table t2 ENGINE=MyISAM select rpad(UUID(),100,' ');
create table t3 select 1 union select UUID();
create table t4 select * from t1 where 3 in (select 1 union select 2 union select UUID() union select 3);
create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3);
@ -453,7 +453,7 @@ master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `mysqltest1`; insert into t1 select "yesterday_24_"
master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE `t2` (
`rpad(UUID(),100,' ')` varchar(100) CHARACTER SET utf8 NOT NULL DEFAULT ''
)
) ENGINE=MyISAM
master-bin.000001 # Table_map # # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE `t3` (
@ -757,7 +757,7 @@ master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `mysqltest1`; insert into t1 select "yesterday_24_"
master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE `t2` (
`rpad(UUID(),100,' ')` varchar(100) CHARACTER SET utf8 NOT NULL DEFAULT ''
)
) ENGINE=MyISAM
master-bin.000001 # Table_map # # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE `t3` (

View File

@ -11,7 +11,7 @@ CREATE SCHEMA IF NOT EXISTS mysqlslap;
USE mysqlslap;
--enable_warnings
CREATE TABLE t1 (id INT, name VARCHAR(64));
CREATE TABLE t1 (id INT, name VARCHAR(64)) ENGINE=MyISAM;
let $query = "INSERT DELAYED INTO t1 VALUES (1, 'Dr. No'), (2, 'From Russia With Love'), (3, 'Goldfinger'), (4, 'Thunderball'), (5, 'You Only Live Twice')";
--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=200 --query=$query --delimiter=";"

View File

@ -1,7 +1,7 @@
# depends on the binlog output
-- source include/have_binlog_format_row.inc
let $rename_event_pos= 623;
let $rename_event_pos= 647;
# Bug#18326: Do not lock table for writing during prepare of statement
# The use of the ps protocol causes extra table maps in the binlog, so

View File

@ -1,7 +1,7 @@
# depends on the binlog output
--source include/have_binlog_format_mixed_or_statement.inc
let $rename_event_pos= 656;
let $rename_event_pos= 684;
-- source extra/rpl_tests/rpl_flsh_tbls.test
# End of 4.1 tests

View File

@ -140,7 +140,7 @@ insert into t1 select "yesterday_24_";
# Test of CREATE TABLE SELECT
create table t2 select rpad(UUID(),100,' ');
create table t2 ENGINE=MyISAM select rpad(UUID(),100,' ');
create table t3 select 1 union select UUID();
create table t4 select * from t1 where 3 in (select 1 union select 2 union select UUID() union select 3);
create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3);

View File

@ -159,7 +159,7 @@ drop table t1;
# Test of ALTER TABLE DELAYED
#
CREATE TABLE t1 (i int(10), index(i) );
CREATE TABLE t1 (i int(10), index(i) ) ENGINE=MyISAM;
ALTER TABLE t1 DISABLE KEYS;
INSERT DELAYED INTO t1 VALUES(1),(2),(3);
ALTER TABLE t1 ENABLE KEYS;

View File

@ -5,6 +5,15 @@
# (Can't be tested with purify :( )
#
# limit the test to engines which support INSERT DELAYED
disable_query_log;
--require r/true.require
select @@global.storage_engine in
("memory","myisam","archive","blackhole") and
@@session.storage_engine in
("memory","myisam","archive","blackhole") as `TRUE`;
enable_query_log;
--disable_warnings
drop table if exists t1;
--enable_warnings

View File

@ -12,6 +12,7 @@
user_limits : Bug#23921 random failure of user_limits.test
concurrent_innodb : BUG#21579 2006-08-11 mleich innodb_concurrent random failures with varying differences
ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Double Whopper
federated_transactions : Bug#29523 Transactions do not work

View File

@ -75,12 +75,10 @@ create event ev_log_general on schedule at now() on completion not preserve
--replace_column 1 USER_HOST
select user_host, db, sql_text from mysql.slow_log
where sql_text like 'select \'events_logs_test\'%';
drop database events_test;
set global event_scheduler=off;
set @@global.long_query_time=default;
set @@session.long_query_time=default;
#
# Safety
#

View File

@ -0,0 +1,26 @@
# Test of scenarios potentially too big for --valgrind or --mem
enable_info;
set storage_engine=maria;
disable_warnings;
drop table if exists t1, t2;
enable_warnings;
create table t1(a char(3));
insert into t1 values("abc");
insert into t1 select "def" from t1;
insert into t1 select "ghi" from t1;
insert into t1 select "jkl" from t1;
insert into t1 select "mno" from t1;
insert into t1 select "pqr" from t1;
insert into t1 select "stu" from t1;
insert into t1 select "vwx" from t1;
insert into t1 select "yza" from t1;
insert into t1 select "ceg" from t1;
insert into t1 select "ikm" from t1;
insert into t1 select "oqs" from t1;
select count(*) from t1;
insert into t1 select "uwy" from t1;
create table t2 select * from t1;
select count(*) from t1;
select count(*) from t2;
drop table t1, t2;
disable_info;

View File

@ -0,0 +1,40 @@
#
# Test that can't be run with --extern
#
-- source include/have_maria.inc
-- source include/have_log_bin.inc
let $default=`select @@global.storage_engine`;
set global storage_engine=maria;
set session storage_engine=maria;
# Initialise
--disable_warnings
drop table if exists t1;
--enable_warnings
SET SQL_WARNINGS=1;
#
# UNIQUE key test
#
# as long as maria cannot rollback, binlog should contain both inserts
#
RESET MASTER;
set binlog_format=statement;
CREATE TABLE t1 (a int primary key);
insert t1 values (1),(2),(3);
--error ER_DUP_ENTRY
insert t1 values (4),(2),(5);
select * from t1;
SHOW BINLOG EVENTS FROM 106;
drop table t1;
set binlog_format=default;
# End of 5.2 tests
--disable_result_log
--disable_query_log
eval set global storage_engine=$default;
--enable_result_log
--enable_query_log

1271
mysql-test/t/maria.test Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,11 @@
# test of MERGE TABLES
#
# MERGE tables require MyISAM tables
let $default=`select @@global.storage_engine`;
set global storage_engine=myisam;
set session storage_engine=myisam;
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6;
drop database if exists mysqltest;
@ -512,3 +517,9 @@ CHECK TABLE tm1;
DROP TABLE tm1, t1, t2;
--echo End of 5.0 tests
--disable_result_log
--disable_query_log
eval set global storage_engine=$default;
--enable_result_log
--enable_query_log

View File

@ -199,7 +199,7 @@ DROP TABLE t1;
--echo # Test for --insert-ignore
--echo #
CREATE TABLE t1 (a int);
CREATE TABLE t1 (a int) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1),(2),(3);
INSERT INTO t1 VALUES (4),(5),(6);
--exec $MYSQL_DUMP --skip-comments --insert-ignore test t1
@ -1463,8 +1463,8 @@ DROP TABLE t1;
# Bug #25993: crashe with a merge table and -c
#
CREATE TABLE t2 (a int);
CREATE TABLE t3 (a int);
CREATE TABLE t2 (a int) ENGINE=MyISAM;
CREATE TABLE t3 (a int) ENGINE=MyISAM;
CREATE TABLE t1 (a int) ENGINE=merge UNION=(t2, t3);
--exec $MYSQL_DUMP --skip-comments -c test
DROP TABLE t1, t2, t3;

View File

@ -0,0 +1,46 @@
###############################################
# #
# Prepared Statements test on MARIA tables #
# #
###############################################
#
# NOTE: PLEASE SEE ps_1general.test (bottom)
# BEFORE ADDING NEW TEST CASES HERE !!!
use test;
-- source include/have_maria.inc
let $type= 'MARIA' ;
-- source include/ps_create.inc
-- source include/ps_renew.inc
-- source include/ps_query.inc
# parameter in SELECT ... MATCH/AGAINST
# case derived from client_test.c: test_bug1500()
--disable_warnings
drop table if exists t2 ;
--enable_warnings
eval create table t2 (s varchar(25), fulltext(s))
ENGINE = $type ;
insert into t2 values ('Gravedigger'), ('Greed'),('Hollow Dogs') ;
commit ;
prepare stmt1 from ' select s from t2 where match (s) against (?) ' ;
set @arg00='Dogs' ;
execute stmt1 using @arg00 ;
prepare stmt1 from ' SELECT s FROM t2
where match (s) against (concat(?,''digger'')) ';
set @arg00='Grave' ;
execute stmt1 using @arg00 ;
drop table t2 ;
-- source include/ps_modify.inc
-- source include/ps_modify1.inc
-- source include/ps_conv.inc
drop table t1, t9;
# End of 4.1 tests

View File

@ -50,9 +50,9 @@ show status like "Qcache_queries_in_cache";
#
# MERGE TABLES with INSERT/UPDATE and DELETE
#
create table t1 (a int not null);
create table t1 (a int not null) ENGINE=MyISAM;
insert into t1 values (1),(2),(3);
create table t2 (a int not null);
create table t2 (a int not null) ENGINE=MyISAM;
insert into t2 values (4),(5),(6);
create table t3 (a int not null) engine=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
# insert
@ -299,7 +299,7 @@ drop table t1;
flush query cache;
reset query cache;
create table t1 (a int not null);
create table t1 (a int not null) ENGINE=MyISAM;
insert into t1 values (1),(2),(3);
select * from t1;
select * from t1;

View File

@ -19,7 +19,7 @@ let $1 = 257;
while ($1)
{
eval drop table if exists t$1;
eval create table t$1(a int);
eval create table t$1(a int) ENGINE=MyISAM;
eval insert into t$1 values (1),(2);
dec $1;
}

View File

@ -335,8 +335,8 @@ select * from t12;
drop table t11, t12, t2;
#insert with subselects
CREATE TABLE t1 (x int);
create table t2 (a int);
CREATE TABLE t1 (x int) ENGINE=MyISAM;
create table t2 (a int) ENGINE=MyISAM;
create table t3 (b int);
insert into t2 values (1);
insert into t3 values (1),(2);
@ -367,7 +367,7 @@ select * from t1;
drop table t1, t2, t3;
#replace with subselects
CREATE TABLE t1 (x int not null, y int, primary key (x));
CREATE TABLE t1 (x int not null, y int, primary key (x)) ENGINE=MyISAM;
create table t2 (a int);
create table t3 (a int);
insert into t2 values (1);

View File

@ -20,17 +20,19 @@ INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
-I$(top_srcdir)/include -I$(srcdir)
pkglib_LIBRARIES = libmysys.a
LDADD = libmysys.a $(top_builddir)/strings/libmystrings.a $(top_builddir)/dbug/libdbug.a
noinst_HEADERS = mysys_priv.h my_static.h
noinst_HEADERS = mysys_priv.h my_static.h my_safehash.h
libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_path.c mf_loadpath.c my_file.c \
my_open.c my_create.c my_dup.c my_seek.c my_read.c \
my_pread.c my_write.c my_getpagesize.c \
my_safehash.c \
mf_keycache.c mf_keycaches.c my_crc32.c \
mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \
mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \
my_malloc.c my_realloc.c my_once.c mulalloc.c \
my_alloc.c safemalloc.c my_new.cc \
my_vle.c my_atomic.c \
my_vle.c my_atomic.c lf_hash.c \
lf_dynarray.c lf_alloc-pin.c \
my_fopen.c my_fstream.c my_getsystime.c \
my_error.c errors.c my_div.c my_messnc.c \
mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \
@ -52,7 +54,8 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
my_gethostbyname.c rijndael.c my_aes.c sha1.c \
my_handler.c my_netware.c my_largepage.c \
my_memmem.c \
my_windac.c my_access.c base64.c my_libwrap.c
my_windac.c my_access.c base64.c my_libwrap.c \
wqueue.c
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
thr_mutex.c thr_rwlock.c \
CMakeLists.txt mf_soundex.c \
@ -126,5 +129,6 @@ test_base64$(EXEEXT): base64.c $(LIBRARIES)
$(LINK) $(FLAGS) -DMAIN ./test_base64.c $(LDADD) $(LIBS)
$(RM) -f ./test_base64.c
# Don't update the files from bitkeeper
%::SCCS/s.%

View File

@ -63,7 +63,7 @@ my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
array->size_of_element=element_size;
if ((array->buffer= init_buffer))
DBUG_RETURN(FALSE);
if (!(array->buffer=(uchar*) my_malloc_ci(element_size*init_alloc,MYF(MY_WME))))
if (!(array->buffer=(uchar*) my_malloc_ci(element_size*init_alloc, MYF(MY_WME))))
{
array->max_element=0;
DBUG_RETURN(TRUE);
@ -179,7 +179,7 @@ uchar *pop_dynamic(DYNAMIC_ARRAY *array)
}
/*
Replace elemnent in array with given element and index
Replace element in array with given element and index
SYNOPSIS
set_dynamic()
@ -200,42 +200,69 @@ my_bool set_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
{
if (idx >= array->elements)
{
if (idx >= array->max_element)
{
uint size;
char *new_ptr;
size=(idx+array->alloc_increment)/array->alloc_increment;
size*= array->alloc_increment;
if (array->buffer == (uchar *)(array + 1))
{
/*
In this senerio, the buffer is statically preallocated,
so we have to create an all-new malloc since we overflowed
*/
if (!(new_ptr= (char *) my_malloc(size *
array->size_of_element,
MYF(MY_WME))))
return 0;
memcpy(new_ptr, array->buffer,
array->elements * array->size_of_element);
}
else
if (!(new_ptr=(char*) my_realloc(array->buffer,size*
array->size_of_element,
MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
return TRUE;
array->buffer= (uchar*) new_ptr;
array->max_element=size;
}
if (idx >= array->max_element && allocate_dynamic(array, idx))
return TRUE;
bzero((uchar*) (array->buffer+array->elements*array->size_of_element),
(idx - array->elements)*array->size_of_element);
(idx - array->elements)*array->size_of_element);
array->elements=idx+1;
}
memcpy(array->buffer+(idx * array->size_of_element),element,
(size_t) array->size_of_element);
(size_t) array->size_of_element);
return FALSE;
}
/*
Ensure that dynamic array has enough elements
SYNOPSIS
allocate_dynamic()
array
max_elements Numbers of elements that is needed
NOTES
Any new allocated element are NOT initialized
RETURN VALUE
FALSE Ok
TRUE Allocation of new memory failed
*/
my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements)
{
if (max_elements >= array->max_element)
{
uint size;
char *new_ptr;
size= (max_elements + array->alloc_increment)/array->alloc_increment;
size*= array->alloc_increment;
if (array->buffer == (uchar *)(array + 1))
{
/*
In this senerio, the buffer is statically preallocated,
so we have to create an all-new malloc since we overflowed
*/
if (!(new_ptr= (char *) my_malloc(size *
array->size_of_element,
MYF(MY_WME))))
return 0;
memcpy(new_ptr, array->buffer,
array->elements * array->size_of_element);
}
else
if (!(new_ptr= (char*) my_realloc(array->buffer,size*
array->size_of_element,
MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
return TRUE;
array->buffer= new_ptr;
array->max_element= size;
}
return FALSE;
}
/*
Get an element from array by given index

523
mysys/lf_alloc-pin.c Normal file
View File

@ -0,0 +1,523 @@
/* QQ: TODO multi-pinbox */
/* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
wait-free concurrent allocator based on pinning addresses
It works as follows: every thread (strictly speaking - every CPU, but
it's too difficult to do) has a small array of pointers. They're called
"pins". Before using an object its address must be stored in this array
(pinned). When an object is no longer necessary its address must be
removed from this array (unpinned). When a thread wants to free() an
object it scans all pins of all threads to see if somebody has this
object pinned. If yes - the object is not freed (but stored in a
"purgatory"). To reduce the cost of a single free() pins are not scanned
on every free() but only added to (thread-local) purgatory. On every
LF_PURGATORY_SIZE free() purgatory is scanned and all unpinned objects
are freed.
Pins are used to solve ABA problem. To use pins one must obey
a pinning protocol:
1. Let's assume that PTR is a shared pointer to an object. Shared means
that any thread may modify it anytime to point to a different object
and free the old object. Later the freed object may be potentially
allocated by another thread. If we're unlucky that other thread may
set PTR to point to this object again. This is ABA problem.
2. Create a local pointer LOCAL_PTR.
3. Pin the PTR in a loop:
do
{
LOCAL_PTR= PTR;
pin(PTR, PIN_NUMBER);
} while (LOCAL_PTR != PTR)
4. It is guaranteed that after the loop has ended, LOCAL_PTR
points to an object (or NULL, if PTR may be NULL), that
will never be freed. It is not guaranteed though
that LOCAL_PTR == PTR (as PTR can change any time)
5. When done working with the object, remove the pin:
unpin(PIN_NUMBER)
6. When copying pins (as in the list traversing loop:
pin(CUR, 1);
while ()
{
do // standard
{ // pinning
NEXT=CUR->next; // loop
pin(NEXT, 0); // see #3
} while (NEXT != CUR->next); // above
...
...
CUR=NEXT;
pin(CUR, 1); // copy pin[0] to pin[1]
}
which keeps CUR address constantly pinned), note than pins may be
copied only upwards (!!!), that is pin[N] to pin[M], M > N.
7. Don't keep the object pinned longer than necessary - the number of
pins you have is limited (and small), keeping an object pinned
prevents its reuse and cause unnecessary mallocs.
Explanations:
3. The loop is important. The following can occur:
thread1> LOCAL_PTR= PTR
thread2> free(PTR); PTR=0;
thread1> pin(PTR, PIN_NUMBER);
now thread1 cannot access LOCAL_PTR, even if it's pinned,
because it points to a freed memory. That is, it *must*
verify that it has indeed pinned PTR, the shared pointer.
6. When a thread wants to free some LOCAL_PTR, and it scans
all lists of pins to see whether it's pinned, it does it
upwards, from low pin numbers to high. Thus another thread
must copy an address from one pin to another in the same
direction - upwards, otherwise the scanning thread may
miss it.
Implementation details:
Pins are given away from a "pinbox". Pinbox is stack-based allocator.
It used dynarray for storing pins, new elements are allocated by dynarray
as necessary, old are pushed in the stack for reuse. ABA is solved by
versioning a pointer - because we use an array, a pointer to pins is 16 bit,
upper 16 bits are used for a version.
It is assumed that pins belong to a thread and are not transferable
between threads (LF_PINS::stack_ends_here being a primary reason
for this limitation).
*/
#include <my_global.h>
#include <my_sys.h>
#include <lf.h>
#define LF_PINBOX_MAX_PINS 65536
static void _lf_pinbox_real_free(LF_PINS *pins);
/*
Initialize a pinbox. Normally called from lf_alloc_init.
See the latter for details.
*/
void lf_pinbox_init(LF_PINBOX *pinbox, uint free_ptr_offset,
lf_pinbox_free_func *free_func, void *free_func_arg)
{
DBUG_ASSERT(free_ptr_offset % sizeof(void *) == 0);
compile_time_assert(sizeof(LF_PINS) == 128);
lf_dynarray_init(&pinbox->pinarray, sizeof(LF_PINS));
pinbox->pinstack_top_ver= 0;
pinbox->pins_in_array= 0;
pinbox->free_ptr_offset= free_ptr_offset;
pinbox->free_func= free_func;
pinbox->free_func_arg= free_func_arg;
}
void lf_pinbox_destroy(LF_PINBOX *pinbox)
{
lf_dynarray_destroy(&pinbox->pinarray);
}
/*
Get pins from a pinbox. Usually called via lf_alloc_get_pins() or
lf_hash_get_pins().
SYNOPSYS
pinbox -
stack_end - a pointer to the end (top/bottom, depending on the
STACK_DIRECTION) of stack. Used for safe alloca. There's
no safety margin deducted, a caller should take care of it,
if necessary.
DESCRIPTION
get a new LF_PINS structure from a stack of unused pins,
or allocate a new one out of dynarray.
NOTE
It is assumed that pins belong to a thread and are not transferable
between threads.
*/
LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox, void *stack_end)
{
uint32 pins, next, top_ver;
LF_PINS *el;
/*
We have an array of max. 64k elements.
The highest index currently allocated is pinbox->pins_in_array.
Freed elements are in a lifo stack, pinstack_top_ver.
pinstack_top_ver is 32 bits; 16 low bits are the index in the
array, to the first element of the list. 16 high bits are a version
(every time the 16 low bits are updated, the 16 high bits are
incremented). Versioniong prevents the ABA problem.
*/
top_ver= pinbox->pinstack_top_ver;
do
{
if (!(pins= top_ver % LF_PINBOX_MAX_PINS))
{
/* the stack of free elements is empty */
pins= my_atomic_add32(&pinbox->pins_in_array, 1)+1;
if (unlikely(pins >= LF_PINBOX_MAX_PINS))
return 0;
/*
note that the first allocated element has index 1 (pins==1).
index 0 is reserved to mean "NULL pointer"
*/
el= (LF_PINS *)_lf_dynarray_lvalue(&pinbox->pinarray, pins);
if (unlikely(!el))
return 0;
break;
}
el= (LF_PINS *)_lf_dynarray_value(&pinbox->pinarray, pins);
next= el->link;
} while (!my_atomic_cas32(&pinbox->pinstack_top_ver, &top_ver,
top_ver-pins+next+LF_PINBOX_MAX_PINS));
/*
set el->link to the index of el in the dynarray (el->link has two usages:
- if element is allocated, it's its own index
- if element is free, it's its next element in the free stack
*/
el->link= pins;
el->purgatory_count= 0;
el->pinbox= pinbox;
el->stack_ends_here= stack_end;
return el;
}
/*
Put pins back to a pinbox. Usually called via lf_alloc_put_pins() or
lf_hash_put_pins().
DESCRIPTION
empty the purgatory (XXX deadlock warning below!),
push LF_PINS structure to a stack
*/
void _lf_pinbox_put_pins(LF_PINS *pins)
{
LF_PINBOX *pinbox= pins->pinbox;
uint32 top_ver, nr;
nr= pins->link;
#ifdef MY_LF_EXTRA_DEBUG
{
int i;
for (i= 0; i < LF_PINBOX_PINS; i++)
DBUG_ASSERT(pins->pin[i] == 0);
}
#endif
/*
XXX this will deadlock if other threads will wait for
the caller to do something after _lf_pinbox_put_pins(),
and they would have pinned addresses that the caller wants to free.
Thus: only free pins when all work is done and nobody can wait for you!!!
*/
while (pins->purgatory_count)
{
_lf_pinbox_real_free(pins);
if (pins->purgatory_count)
{
my_atomic_rwlock_wrunlock(&pins->pinbox->pinarray.lock);
pthread_yield();
my_atomic_rwlock_wrlock(&pins->pinbox->pinarray.lock);
}
}
top_ver= pinbox->pinstack_top_ver;
do
{
pins->link= top_ver % LF_PINBOX_MAX_PINS;
} while (!my_atomic_cas32(&pinbox->pinstack_top_ver, &top_ver,
top_ver-pins->link+nr+LF_PINBOX_MAX_PINS));
return;
}
static int ptr_cmp(void **a, void **b)
{
return *a < *b ? -1 : *a == *b ? 0 : 1;
}
#define add_to_purgatory(PINS, ADDR) \
do \
{ \
*(void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset)= \
(PINS)->purgatory; \
(PINS)->purgatory= (ADDR); \
(PINS)->purgatory_count++; \
} while (0)
/*
Free an object allocated via pinbox allocator
DESCRIPTION
add an object to purgatory. if necessary, call _lf_pinbox_real_free()
to actually free something.
*/
void _lf_pinbox_free(LF_PINS *pins, void *addr)
{
add_to_purgatory(pins, addr);
if (pins->purgatory_count % LF_PURGATORY_SIZE)
_lf_pinbox_real_free(pins);
}
struct st_harvester {
void **granary;
int npins;
};
/*
callback for _lf_dynarray_iterate:
scan all pins of all threads and accumulate all pins
*/
static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
{
int i;
LF_PINS *el_end= el+min(hv->npins, LF_DYNARRAY_LEVEL_LENGTH);
for (; el < el_end; el++)
{
for (i= 0; i < LF_PINBOX_PINS; i++)
{
void *p= el->pin[i];
if (p)
*hv->granary++= p;
}
}
/*
hv->npins may become negative below, but it means that
we're on the last dynarray page and harvest_pins() won't be
called again. We don't bother to make hv->npins() correct
(that is 0) in this case.
*/
hv->npins-= LF_DYNARRAY_LEVEL_LENGTH;
return 0;
}
/*
callback for _lf_dynarray_iterate:
scan all pins of all threads and see if addr is present there
*/
static int match_pins(LF_PINS *el, void *addr)
{
int i;
LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH;
for (; el < el_end; el++)
for (i= 0; i < LF_PINBOX_PINS; i++)
if (el->pin[i] == addr)
return 1;
return 0;
}
#if STACK_DIRECTION < 0
#define available_stack_size(END,CUR) (long) ((char*)(CUR) - (char*)(END))
#else
#define available_stack_size(END,CUR) (long) ((char*)(END) - (char*)(CUR))
#endif
/*
Scan the purgatory and free everything that can be freed
*/
static void _lf_pinbox_real_free(LF_PINS *pins)
{
int npins, alloca_size;
void *list, **addr;
struct st_lf_alloc_node *first, *last= NULL;
LF_PINBOX *pinbox= pins->pinbox;
npins= pinbox->pins_in_array+1;
#ifdef HAVE_ALLOCA
alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins;
/* create a sorted list of pinned addresses, to speed up searches */
if (available_stack_size(&pinbox, pins->stack_ends_here) > alloca_size)
{
struct st_harvester hv;
addr= (void **) alloca(alloca_size);
hv.granary= addr;
hv.npins= npins;
/* scan the dynarray and accumulate all pinned addresses */
_lf_dynarray_iterate(&pinbox->pinarray,
(lf_dynarray_func)harvest_pins, &hv);
npins= hv.granary-addr;
/* and sort them */
if (npins)
qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
}
else
#endif
addr= 0;
list= pins->purgatory;
pins->purgatory= 0;
pins->purgatory_count= 0;
while (list)
{
void *cur= list;
list= *(void **)((char *)cur+pinbox->free_ptr_offset);
if (npins)
{
if (addr) /* use binary search */
{
void **a, **b, **c;
for (a= addr, b= addr+npins-1, c= a+(b-a)/2; (b-a) > 1; c= a+(b-a)/2)
if (cur == *c)
a= b= c;
else if (cur > *c)
a= c;
else
b= c;
if (cur == *a || cur == *b)
goto found;
}
else /* no alloca - no cookie. linear search here */
{
if (_lf_dynarray_iterate(&pinbox->pinarray,
(lf_dynarray_func)match_pins, cur))
goto found;
}
}
/* not pinned - freeing */
if (last)
last= last->next= (struct st_lf_alloc_node *)cur;
else
first= last= (struct st_lf_alloc_node *)cur;
continue;
found:
/* pinned - keeping */
add_to_purgatory(pins, cur);
}
if (last)
pinbox->free_func(first, last, pinbox->free_func_arg);
}
/* lock-free memory allocator for fixed-size objects */
LF_REQUIRE_PINS(1);
/*
callback for _lf_pinbox_real_free to free a list of unpinned objects -
add it back to the allocator stack
DESCRIPTION
'first' and 'last' are the ends of the linked list of st_lf_alloc_node's:
first->el->el->....->el->last. Use first==last to free only one element.
*/
static void alloc_free(struct st_lf_alloc_node *first,
struct st_lf_alloc_node *last,
LF_ALLOCATOR *allocator)
{
struct st_lf_alloc_node *tmp;
tmp= allocator->top;
do
{
last->next= tmp;
} while (!my_atomic_casptr((void **)&allocator->top, (void **)&tmp, first) &&
LF_BACKOFF);
}
/*
initialize lock-free allocator
SYNOPSYS
allocator -
size a size of an object to allocate
free_ptr_offset an offset inside the object to a sizeof(void *)
memory that is guaranteed to be unused after
the object is put in the purgatory. Unused by ANY
thread, not only the purgatory owner.
This memory will be used to link waiting-to-be-freed
objects in a purgatory list.
*/
void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset)
{
lf_pinbox_init(&allocator->pinbox, free_ptr_offset,
(lf_pinbox_free_func *)alloc_free, allocator);
allocator->top= 0;
allocator->mallocs= 0;
allocator->element_size= size;
DBUG_ASSERT(size >= sizeof(void*) + free_ptr_offset);
}
/*
destroy the allocator, free everything that's in it
NOTE
As every other init/destroy function here and elsewhere it
is not thread safe. No, this function is no different, ensure
that no thread needs the allocator before destroying it.
We are not responsible for any damage that may be caused by
accessing the allocator when it is being or has been destroyed.
Oh yes, and don't put your cat in a microwave.
*/
void lf_alloc_destroy(LF_ALLOCATOR *allocator)
{
struct st_lf_alloc_node *node= allocator->top;
while (node)
{
struct st_lf_alloc_node *tmp= node->next;
my_free((void *)node, MYF(0));
node= tmp;
}
lf_pinbox_destroy(&allocator->pinbox);
allocator->top= 0;
}
/*
Allocate and return an new object.
DESCRIPTION
Pop an unused object from the stack or malloc it is the stack is empty.
pin[0] is used, it's removed on return.
*/
void *_lf_alloc_new(LF_PINS *pins)
{
LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg);
struct st_lf_alloc_node *node;
for (;;)
{
do
{
node= allocator->top;
_lf_pin(pins, 0, node);
} while (node != allocator->top && LF_BACKOFF);
if (!node)
{
node= (void *)my_malloc(allocator->element_size, MYF(MY_WME));
#ifdef MY_LF_EXTRA_DEBUG
if (likely(node))
my_atomic_add32(&allocator->mallocs, 1);
#endif
break;
}
if (my_atomic_casptr((void **)&allocator->top, (void *)&node, node->next))
break;
}
_lf_unpin(pins, 0);
return node;
}
/*
count the number of objects in a pool.
NOTE
This is NOT thread-safe !!!
*/
uint lf_alloc_pool_count(LF_ALLOCATOR *allocator)
{
uint i;
struct st_lf_alloc_node *node;
for (node= allocator->top, i= 0; node; node= node->next, i++)
/* no op */;
return i;
}

208
mysys/lf_dynarray.c Normal file
View File

@ -0,0 +1,208 @@
/* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Analog of DYNAMIC_ARRAY that never reallocs
(so no pointer into the array may ever become invalid).
Memory is allocated in non-contiguous chunks.
This data structure is not space efficient for sparse arrays.
Every element is aligned to sizeof(element) boundary
(to avoid false sharing if element is big enough).
LF_DYNARRAY is a recursive structure. On the zero level
LF_DYNARRAY::level[0] it's an array of LF_DYNARRAY_LEVEL_LENGTH elements,
on the first level it's an array of LF_DYNARRAY_LEVEL_LENGTH pointers
to arrays of elements, on the second level it's an array of pointers
to arrays of pointers to arrays of elements. And so on.
With four levels the number of elements is limited to 4311810304
(but as in all functions index is uint, the real limit is 2^32-1)
Actually, it's wait-free, not lock-free ;-)
*/
#include <my_global.h>
#include <strings.h>
#include <my_sys.h>
#include <lf.h>
void lf_dynarray_init(LF_DYNARRAY *array, uint element_size)
{
bzero(array, sizeof(*array));
array->size_of_element= element_size;
my_atomic_rwlock_init(&array->lock);
}
static void recursive_free(void **alloc, int level)
{
if (!alloc)
return;
if (level)
{
int i;
for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
recursive_free(alloc[i], level-1);
my_free((void *)alloc, MYF(0));
}
else
my_free(alloc[-1], MYF(0));
}
void lf_dynarray_destroy(LF_DYNARRAY *array)
{
int i;
for (i= 0; i < LF_DYNARRAY_LEVELS; i++)
recursive_free(array->level[i], i);
my_atomic_rwlock_destroy(&array->lock);
}
static const ulong dynarray_idxes_in_prev_levels[LF_DYNARRAY_LEVELS]=
{
0, /* +1 here to to avoid -1's below */
LF_DYNARRAY_LEVEL_LENGTH,
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH +
LF_DYNARRAY_LEVEL_LENGTH,
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH *
LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH
};
static const ulong dynarray_idxes_in_prev_level[LF_DYNARRAY_LEVELS]=
{
0, /* +1 here to to avoid -1's below */
LF_DYNARRAY_LEVEL_LENGTH,
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH,
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
LF_DYNARRAY_LEVEL_LENGTH,
};
/*
Returns a valid lvalue pointer to the element number 'idx'.
Allocates memory if necessary.
*/
void *_lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx)
{
void * ptr, * volatile * ptr_ptr= 0;
int i;
for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--)
/* no-op */;
ptr_ptr= &array->level[i];
idx-= dynarray_idxes_in_prev_levels[i];
for (; i > 0; i--)
{
if (!(ptr= *ptr_ptr))
{
void *alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * sizeof(void *),
MYF(MY_WME|MY_ZEROFILL));
if (unlikely(!alloc))
return(NULL);
if (my_atomic_casptr(ptr_ptr, &ptr, alloc))
ptr= alloc;
else
my_free(alloc, MYF(0));
}
ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i];
idx%= dynarray_idxes_in_prev_level[i];
}
if (!(ptr= *ptr_ptr))
{
void *alloc, *data;
alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * array->size_of_element +
max(array->size_of_element, sizeof(void *)),
MYF(MY_WME|MY_ZEROFILL));
if (unlikely(!alloc))
return(NULL);
/* reserve the space for free() address */
data= alloc + sizeof(void *);
{ /* alignment */
intptr mod= ((intptr)data) % array->size_of_element;
if (mod)
data+= array->size_of_element - mod;
}
((void **)data)[-1]= alloc; /* free() will need the original pointer */
if (my_atomic_casptr(ptr_ptr, &ptr, data))
ptr= data;
else
my_free(alloc, MYF(0));
}
return ptr + array->size_of_element * idx;
}
/*
Returns a pointer to the element number 'idx'
or NULL if an element does not exists
*/
void *_lf_dynarray_value(LF_DYNARRAY *array, uint idx)
{
void * ptr, * volatile * ptr_ptr= 0;
int i;
for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--)
/* no-op */;
ptr_ptr= &array->level[i];
idx-= dynarray_idxes_in_prev_levels[i];
for (; i > 0; i--)
{
if (!(ptr= *ptr_ptr))
return(NULL);
ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i];
idx %= dynarray_idxes_in_prev_level[i];
}
if (!(ptr= *ptr_ptr))
return(NULL);
return ptr + array->size_of_element * idx;
}
static int recursive_iterate(LF_DYNARRAY *array, void *ptr, int level,
lf_dynarray_func func, void *arg)
{
int res, i;
if (!ptr)
return 0;
if (!level)
return func(ptr, arg);
for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
if ((res= recursive_iterate(array, ((void **)ptr)[i], level-1, func, arg)))
return res;
return 0;
}
/*
Calls func(array, arg) on every array of LF_DYNARRAY_LEVEL_LENGTH elements
in lf_dynarray.
DESCRIPTION
lf_dynarray consists of a set of arrays, LF_DYNARRAY_LEVEL_LENGTH elements
each. _lf_dynarray_iterate() calls user-supplied function on every array
from the set. It is the fastest way to scan the array, faster than
for (i=0; i < N; i++) { func(_lf_dynarray_value(dynarray, i)); }
NOTE
if func() returns non-zero, the scan is aborted
*/
int _lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg)
{
int i, res;
for (i= 0; i < LF_DYNARRAY_LEVELS; i++)
if ((res= recursive_iterate(array, array->level[i], i, func, arg)))
return res;
return 0;
}

493
mysys/lf_hash.c Normal file
View File

@ -0,0 +1,493 @@
/* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
extensible hash
TODO
try to get rid of dummy nodes ?
for non-unique hash, count only _distinct_ values
(but how to do it in lf_hash_delete ?)
*/
#include <my_global.h>
#include <m_string.h>
#include <my_sys.h>
#include <my_bit.h>
#include <lf.h>
LF_REQUIRE_PINS(3);
/* An element of the list */
typedef struct {
intptr volatile link; /* a pointer to the next element in a listand a flag */
uint32 hashnr; /* reversed hash number, for sorting */
const uchar *key;
size_t keylen;
/*
data is stored here, directly after the keylen.
thus the pointer to data is (void*)(slist_element_ptr+1)
*/
} LF_SLIST;
/*
a structure to pass the context (pointers two the three successive elements
in a list) from lfind to linsert/ldelete
*/
typedef struct {
intptr volatile *prev;
LF_SLIST *curr, *next;
} CURSOR;
/*
the last bit in LF_SLIST::link is a "deleted" flag.
the helper macros below convert it to a pure pointer or a pure flag
*/
#define PTR(V) (LF_SLIST *)((V) & (~(intptr)1))
#define DELETED(V) ((V) & 1)
/*
DESCRIPTION
Search for hashnr/key/keylen in the list starting from 'head' and
position the cursor. The list is ORDER BY hashnr, key
RETURN
0 - not found
1 - found
NOTE
cursor is positioned in either case
pins[0..2] are used, they are NOT removed on return
*/
static int lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins)
{
uint32 cur_hashnr;
const uchar *cur_key;
uint cur_keylen;
intptr link;
retry:
cursor->prev= (intptr *)head;
do { /* PTR() isn't necessary below, head is a dummy node */
cursor->curr= (LF_SLIST *)(*cursor->prev);
_lf_pin(pins, 1, cursor->curr);
} while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
for (;;)
{
if (unlikely(!cursor->curr))
return 0; /* end of the list */
do {
/* QQ: XXX or goto retry ? */
link= cursor->curr->link;
cursor->next= PTR(link);
_lf_pin(pins, 0, cursor->next);
} while (link != cursor->curr->link && LF_BACKOFF);
cur_hashnr= cursor->curr->hashnr;
cur_key= cursor->curr->key;
cur_keylen= cursor->curr->keylen;
if (*cursor->prev != (intptr)cursor->curr)
{
(void)LF_BACKOFF;
goto retry;
}
if (!DELETED(link))
{
if (cur_hashnr >= hashnr)
{
int r= 1;
if (cur_hashnr > hashnr ||
(r= my_strnncoll(cs, (uchar*) cur_key, cur_keylen, (uchar*) key,
keylen)) >= 0)
return !r;
}
cursor->prev= &(cursor->curr->link);
_lf_pin(pins, 2, cursor->curr);
}
else
{
/*
we found a deleted node - be nice, help the other thread
and remove this deleted node
*/
if (my_atomic_casptr((void **)cursor->prev,
(void **)&cursor->curr, cursor->next))
_lf_alloc_free(pins, cursor->curr);
else
{
(void)LF_BACKOFF;
goto retry;
}
}
cursor->curr= cursor->next;
_lf_pin(pins, 1, cursor->curr);
}
}
/*
DESCRIPTION
insert a 'node' in the list that starts from 'head' in the correct
position (as found by lfind)
RETURN
0 - inserted
not 0 - a pointer to a duplicate (not pinned and thus unusable)
NOTE
it uses pins[0..2], on return all pins are removed.
if there're nodes with the same key value, a new node is added before them.
*/
static LF_SLIST *linsert(LF_SLIST * volatile *head, CHARSET_INFO *cs,
LF_SLIST *node, LF_PINS *pins, uint flags)
{
CURSOR cursor;
int res;
for (;;)
{
if (lfind(head, cs, node->hashnr, node->key, node->keylen,
&cursor, pins) &&
(flags & LF_HASH_UNIQUE))
{
res= 0; /* duplicate found */
break;
}
else
{
node->link= (intptr)cursor.curr;
DBUG_ASSERT(node->link != (intptr)node); /* no circular references */
DBUG_ASSERT(cursor.prev != &node->link); /* no circular references */
if (my_atomic_casptr((void **)cursor.prev, (void **)&cursor.curr, node))
{
res= 1; /* inserted ok */
break;
}
}
}
_lf_unpin(pins, 0);
_lf_unpin(pins, 1);
_lf_unpin(pins, 2);
/*
Note that cursor.curr is not pinned here and the pointer is unreliable,
the object may dissapear anytime. But if it points to a dummy node, the
pointer is safe, because dummy nodes are never freed - initialize_bucket()
uses this fact.
*/
return res ? 0 : cursor.curr;
}
/*
DESCRIPTION
deletes a node as identified by hashnr/keey/keylen from the list
that starts from 'head'
RETURN
0 - ok
1 - not found
NOTE
it uses pins[0..2], on return all pins are removed.
*/
static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
const uchar *key, uint keylen, LF_PINS *pins)
{
CURSOR cursor;
int res;
for (;;)
{
if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins))
{
res= 1; /* not found */
break;
}
else
{
/* mark the node deleted */
if (my_atomic_casptr((void **)&(cursor.curr->link),
(void **)&cursor.next,
(void *)(((intptr)cursor.next) | 1)))
{
/* and remove it from the list */
if (my_atomic_casptr((void **)cursor.prev,
(void **)&cursor.curr, cursor.next))
_lf_alloc_free(pins, cursor.curr);
else
{
/*
somebody already "helped" us and removed the node ?
Let's check if we need to help that someone too!
(to ensure the number of "set DELETED flag" actions
is equal to the number of "remove from the list" actions)
*/
lfind(head, cs, hashnr, key, keylen, &cursor, pins);
}
res= 0;
break;
}
}
}
_lf_unpin(pins, 0);
_lf_unpin(pins, 1);
_lf_unpin(pins, 2);
return res;
}
/*
DESCRIPTION
searches for a node as identified by hashnr/keey/keylen in the list
that starts from 'head'
RETURN
0 - not found
node - found
NOTE
it uses pins[0..2], on return the pin[2] keeps the node found
all other pins are removed.
*/
static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs,
uint32 hashnr, const uchar *key, uint keylen,
LF_PINS *pins)
{
CURSOR cursor;
int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins);
if (res)
_lf_pin(pins, 2, cursor.curr);
_lf_unpin(pins, 0);
_lf_unpin(pins, 1);
return res ? cursor.curr : 0;
}
static inline const uchar* hash_key(const LF_HASH *hash,
const uchar *record, size_t *length)
{
if (hash->get_key)
return (*hash->get_key)(record, length, 0);
*length= hash->key_length;
return record + hash->key_offset;
}
/*
compute the hash key value from the raw key.
note, that the hash value is limited to 2^31, because we need one
bit to distinguish between normal and dummy nodes.
*/
static inline uint calc_hash(LF_HASH *hash, const uchar *key, uint keylen)
{
ulong nr1= 1, nr2= 4;
hash->charset->coll->hash_sort(hash->charset, (uchar*) key, keylen,
&nr1, &nr2);
return nr1 & INT_MAX32;
}
#define MAX_LOAD 1.0 /* average number of elements in a bucket */
static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *);
/*
Initializes lf_hash, the arguments are compatible with hash_init
*/
void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
uint key_offset, uint key_length, hash_get_key get_key,
CHARSET_INFO *charset)
{
lf_alloc_init(&hash->alloc, sizeof(LF_SLIST)+element_size,
offsetof(LF_SLIST, key));
lf_dynarray_init(&hash->array, sizeof(LF_SLIST *));
hash->size= 1;
hash->count= 0;
hash->element_size= element_size;
hash->flags= flags;
hash->charset= charset ? charset : &my_charset_bin;
hash->key_offset= key_offset;
hash->key_length= key_length;
hash->get_key= get_key;
DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length);
}
void lf_hash_destroy(LF_HASH *hash)
{
LF_SLIST *el, **head= (LF_SLIST **)_lf_dynarray_value(&hash->array, 0);
if (unlikely(!head))
return;
el= *head;
while (el)
{
intptr next= el->link;
if (el->hashnr & 1)
lf_alloc_direct_free(&hash->alloc, el); /* normal node */
else
my_free((void *)el, MYF(0)); /* dummy node */
el= (LF_SLIST *)next;
}
lf_alloc_destroy(&hash->alloc);
lf_dynarray_destroy(&hash->array);
}
/*
DESCRIPTION
inserts a new element to a hash. it will have a _copy_ of
data, not a pointer to it.
RETURN
0 - inserted
1 - didn't (unique key conflict)
-1 - out of memory
NOTE
see linsert() for pin usage notes
*/
int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data)
{
int csize, bucket, hashnr;
LF_SLIST *node, * volatile *el;
lf_rwlock_by_pins(pins);
node= (LF_SLIST *)_lf_alloc_new(pins);
if (unlikely(!node))
return -1;
memcpy(node+1, data, hash->element_size);
node->key= hash_key(hash, (uchar *)(node+1), &node->keylen);
hashnr= calc_hash(hash, node->key, node->keylen);
bucket= hashnr % hash->size;
el= _lf_dynarray_lvalue(&hash->array, bucket);
if (unlikely(!el))
return -1;
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
return -1;
node->hashnr= my_reverse_bits(hashnr) | 1; /* normal node */
if (linsert(el, hash->charset, node, pins, hash->flags))
{
_lf_alloc_free(pins, node);
lf_rwunlock_by_pins(pins);
return 1;
}
csize= hash->size;
if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD)
my_atomic_cas32(&hash->size, &csize, csize*2);
lf_rwunlock_by_pins(pins);
return 0;
}
/*
DESCRIPTION
deletes an element with the given key from the hash (if a hash is
not unique and there're many elements with this key - the "first"
matching element is deleted)
RETURN
0 - deleted
1 - didn't (not found)
-1 - out of memory
NOTE
see ldelete() for pin usage notes
*/
int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
{
LF_SLIST * volatile *el;
uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
bucket= hashnr % hash->size;
lf_rwlock_by_pins(pins);
el= _lf_dynarray_lvalue(&hash->array, bucket);
if (unlikely(!el))
return -1;
/*
note that we still need to initialize_bucket here,
we cannot return "node not found", because an old bucket of that
node may've been split and the node was assigned to a new bucket
that was never accessed before and thus is not initialized.
*/
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
return -1;
if (ldelete(el, hash->charset, my_reverse_bits(hashnr) | 1,
(uchar *)key, keylen, pins))
{
lf_rwunlock_by_pins(pins);
return 1;
}
my_atomic_add32(&hash->count, -1);
lf_rwunlock_by_pins(pins);
return 0;
}
/*
RETURN
a pointer to an element with the given key (if a hash is not unique and
there're many elements with this key - the "first" matching element)
NULL if nothing is found
MY_ERRPTR if OOM
NOTE
see lsearch() for pin usage notes
*/
void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
{
LF_SLIST * volatile *el, *found;
uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
bucket= hashnr % hash->size;
lf_rwlock_by_pins(pins);
el= _lf_dynarray_lvalue(&hash->array, bucket);
if (unlikely(!el))
return MY_ERRPTR;
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
return MY_ERRPTR;
found= lsearch(el, hash->charset, my_reverse_bits(hashnr) | 1,
(uchar *)key, keylen, pins);
lf_rwunlock_by_pins(pins);
return found ? found+1 : 0;
}
static const uchar *dummy_key= "";
/*
RETURN
0 - ok
-1 - out of memory
*/
static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node,
uint bucket, LF_PINS *pins)
{
uint parent= my_clear_highest_bit(bucket);
LF_SLIST *dummy= (LF_SLIST *)my_malloc(sizeof(LF_SLIST), MYF(MY_WME));
LF_SLIST **tmp= 0, *cur;
LF_SLIST * volatile *el= _lf_dynarray_lvalue(&hash->array, parent);
if (unlikely(!el || !dummy))
return -1;
if (*el == NULL && bucket &&
unlikely(initialize_bucket(hash, el, parent, pins)))
return -1;
dummy->hashnr= my_reverse_bits(bucket) | 0; /* dummy node */
dummy->key= (char*) dummy_key;
dummy->keylen= 0;
if ((cur= linsert(el, hash->charset, dummy, pins, LF_HASH_UNIQUE)))
{
my_free((void *)dummy, MYF(0));
dummy= cur;
}
my_atomic_casptr((void **)node, (void **)&tmp, dummy);
/*
note that if the CAS above failed (after linsert() succeeded),
it would mean that some other thread has executed linsert() for
the same dummy node, its linsert() failed, it picked up our
dummy node (in "dummy= cur") and executed the same CAS as above.
Which means that even if CAS above failed we don't need to retry,
and we should not free(dummy) - there's no memory leak here
*/
return 0;
}

View File

@ -1701,6 +1701,7 @@ int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
my_bool append_cache;
my_off_t pos_in_file;
DBUG_ENTER("my_b_flush_io_cache");
DBUG_PRINT("enter", ("cache: 0x%lx", (long) info));
if (!(append_cache = (info->type == SEQ_READ_APPEND)))
need_append_buffer_lock=0;

View File

@ -105,6 +105,7 @@
#include <keycache.h>
#include "my_static.h"
#include <m_string.h>
#include <my_bit.h>
#include <errno.h>
#include <stdarg.h>
@ -1262,12 +1263,12 @@ static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
KEYCACHE_THREAD_TRACE("unlink_block");
#if defined(KEYCACHE_DEBUG)
KEYCACHE_DBUG_ASSERT(keycache->blocks_available != 0);
keycache->blocks_available--;
KEYCACHE_DBUG_PRINT("unlink_block",
("unlinked block %u status=%x #requests=%u #available=%u",
BLOCK_NUMBER(block), block->status,
block->requests, keycache->blocks_available));
KEYCACHE_DBUG_ASSERT(keycache->blocks_available >= 0);
#endif
}
@ -2360,9 +2361,9 @@ restart:
(block->hash_link->diskpos == filepos)));
*page_st=page_status;
KEYCACHE_DBUG_PRINT("find_key_block",
("fd: %d pos: %lu block->status: %u page_status: %u",
("fd: %d pos: %lu block->status: %u page_status: %d",
file, (ulong) filepos, block->status,
(uint) page_status));
page_status));
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_keycache2",
@ -2513,10 +2514,10 @@ static void read_block(KEY_CACHE *keycache,
*/
uchar *key_cache_read(KEY_CACHE *keycache,
File file, my_off_t filepos, int level,
uchar *buff, uint length,
uint block_length __attribute__((unused)),
int return_buffer __attribute__((unused)))
File file, my_off_t filepos, int level,
uchar *buff, uint length,
uint block_length __attribute__((unused)),
int return_buffer __attribute__((unused)))
{
my_bool locked_and_incremented= FALSE;
int error=0;
@ -2534,12 +2535,13 @@ uchar *key_cache_read(KEY_CACHE *keycache,
uint status;
int page_st;
/*
/*
When the key cache is once initialized, we use the cache_lock to
reliably distinguish the cases of normal operation, resizing, and
disabled cache. We always increment and decrement
'cnt_for_resize_op' so that a resizer can wait for pending I/O.
*/
*/
keycache_pthread_mutex_lock(&keycache->cache_lock);
/*
Cache resizing has two phases: Flushing and re-initializing. In
@ -2566,7 +2568,7 @@ uchar *key_cache_read(KEY_CACHE *keycache,
do
{
/* Cache could be disabled in a later iteration. */
if (!keycache->can_be_used)
goto no_key_cache;
/* Start reading at the beginning of the cache block. */
@ -2976,9 +2978,10 @@ int key_cache_write(KEY_CACHE *keycache,
int error=0;
DBUG_ENTER("key_cache_write");
DBUG_PRINT("enter",
("fd: %u pos: %lu length: %u block_length: %u key_block_length: %u",
(uint) file, (ulong) filepos, length, block_length,
keycache ? keycache->key_cache_block_size : 0));
("fd: %u pos: %lu length: %u block_length: %u"
" key_block_length: %u",
(uint) file, (ulong) filepos, length, block_length,
keycache ? keycache->key_cache_block_size : 0));
if (!dont_write)
{
@ -3170,7 +3173,7 @@ int key_cache_write(KEY_CACHE *keycache,
if (!dont_write)
{
/* Not used in the server. buff has been written to disk at start. */
/* Not used in the server. buff has been written to disk at start. */
if ((block->status & BLOCK_CHANGED) &&
(!offset && read_length >= keycache->key_cache_block_size))
link_to_file_list(keycache, block, block->hash_link->file, 1);
@ -3184,7 +3187,6 @@ int key_cache_write(KEY_CACHE *keycache,
a flush.
*/
block->status&= ~BLOCK_FOR_UPDATE;
set_if_smaller(block->offset, offset);
set_if_bigger(block->length, read_length+offset);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2003 MySQL AB
/* Copyright (C) 2003-2007 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -25,269 +25,7 @@
#include <keycache.h>
#include <hash.h>
#include <m_string.h>
/*****************************************************************************
General functions to handle SAFE_HASH objects.
A SAFE_HASH object is used to store the hash, the mutex and default value
needed by the rest of the key cache code.
This is a separate struct to make it easy to later reuse the code for other
purposes
All entries are linked in a list to allow us to traverse all elements
and delete selected ones. (HASH doesn't allow any easy ways to do this).
*****************************************************************************/
/*
Struct to store a key and pointer to object
*/
typedef struct st_safe_hash_entry
{
uchar *key;
uint length;
uchar *data;
struct st_safe_hash_entry *next, **prev;
} SAFE_HASH_ENTRY;
typedef struct st_safe_hash_with_default
{
#ifdef THREAD
rw_lock_t mutex;
#endif
HASH hash;
uchar *default_value;
SAFE_HASH_ENTRY *root;
} SAFE_HASH;
/*
Free a SAFE_HASH_ENTRY
This function is called by the hash object on delete
*/
static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
{
DBUG_ENTER("free_assign_entry");
my_free((uchar*) entry, MYF(0));
DBUG_VOID_RETURN;
}
/* Get key and length for a SAFE_HASH_ENTRY */
static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length=entry->length;
return (uchar*) entry->key;
}
/*
Init a SAFE_HASH object
SYNOPSIS
safe_hash_init()
hash safe_hash handler
elements Expected max number of elements
default_value default value
NOTES
In case of error we set hash->default_value to 0 to allow one to call
safe_hash_free on an object that couldn't be initialized.
RETURN
0 ok
1 error
*/
static my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
uchar *default_value)
{
DBUG_ENTER("safe_hash");
if (hash_init(&hash->hash, &my_charset_bin, elements,
0, 0, (hash_get_key) safe_hash_entry_get,
(void (*)(void*)) safe_hash_entry_free, 0))
{
hash->default_value= 0;
DBUG_RETURN(1);
}
my_rwlock_init(&hash->mutex, 0);
hash->default_value= default_value;
hash->root= 0;
DBUG_RETURN(0);
}
/*
Free a SAFE_HASH object
NOTES
This is safe to call on any object that has been sent to safe_hash_init()
*/
static void safe_hash_free(SAFE_HASH *hash)
{
/*
Test if safe_hash_init succeeded. This will also guard us against multiple
free calls.
*/
if (hash->default_value)
{
hash_free(&hash->hash);
rwlock_destroy(&hash->mutex);
hash->default_value=0;
}
}
/*
Return the value stored for a key or default value if no key
*/
static uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length)
{
uchar *result;
DBUG_ENTER("safe_hash_search");
rw_rdlock(&hash->mutex);
result= hash_search(&hash->hash, key, length);
rw_unlock(&hash->mutex);
if (!result)
result= hash->default_value;
else
result= ((SAFE_HASH_ENTRY*) result)->data;
DBUG_PRINT("exit",("data: 0x%lx", (long) result));
DBUG_RETURN(result);
}
/*
Associate a key with some data
SYONOPSIS
safe_hash_set()
hash Hash handle
key key (path to table etc..)
length Length of key
data data to to associate with the data
NOTES
This can be used both to insert a new entry and change an existing
entry.
If one associates a key with the default key cache, the key is deleted
RETURN
0 ok
1 error (Can only be EOM). In this case my_message() is called.
*/
static my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
uchar *data)
{
SAFE_HASH_ENTRY *entry;
my_bool error= 0;
DBUG_ENTER("safe_hash_set");
DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data));
rw_wrlock(&hash->mutex);
entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
if (data == hash->default_value)
{
/*
The key is to be associated with the default entry. In this case
we can just delete the entry (if it existed) from the hash as a
search will return the default entry
*/
if (!entry) /* nothing to do */
goto end;
/* unlink entry from list */
if ((*entry->prev= entry->next))
entry->next->prev= entry->prev;
hash_delete(&hash->hash, (uchar*) entry);
goto end;
}
if (entry)
{
/* Entry existed; Just change the pointer to point at the new data */
entry->data= data;
}
else
{
if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
MYF(MY_WME))))
{
error= 1;
goto end;
}
entry->key= (uchar*) (entry +1);
memcpy((char*) entry->key, (char*) key, length);
entry->length= length;
entry->data= data;
/* Link entry to list */
if ((entry->next= hash->root))
entry->next->prev= &entry->next;
entry->prev= &hash->root;
hash->root= entry;
if (my_hash_insert(&hash->hash, (uchar*) entry))
{
/* This can only happen if hash got out of memory */
my_free((char*) entry, MYF(0));
error= 1;
goto end;
}
}
end:
rw_unlock(&hash->mutex);
DBUG_RETURN(error);
}
/*
Change all entres with one data value to another data value
SYONOPSIS
safe_hash_change()
hash Hash handle
old_data Old data
new_data Change all 'old_data' to this
NOTES
We use the linked list to traverse all elements in the hash as
this allows us to delete elements in the case where 'new_data' is the
default value.
*/
static void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
{
SAFE_HASH_ENTRY *entry, *next;
DBUG_ENTER("safe_hash_set");
rw_wrlock(&hash->mutex);
for (entry= hash->root ; entry ; entry= next)
{
next= entry->next;
if (entry->data == old_data)
{
if (new_data == hash->default_value)
{
if ((*entry->prev= entry->next))
entry->next->prev= entry->prev;
hash_delete(&hash->hash, (uchar*) entry);
}
else
entry->data= new_data;
}
}
rw_unlock(&hash->mutex);
DBUG_VOID_RETURN;
}
#include "my_safehash.h"
/*****************************************************************************
Functions to handle the key cache objects
@ -315,6 +53,7 @@ void multi_keycache_free(void)
multi_key_cache_search()
key key to find (usually table path)
uint length Length of key.
def Default value if no key cache
NOTES
This function is coded in such a way that we will return the
@ -325,11 +64,13 @@ void multi_keycache_free(void)
key cache to use
*/
KEY_CACHE *multi_key_cache_search(uchar *key, uint length)
KEY_CACHE *multi_key_cache_search(uchar *key, uint length,
KEY_CACHE *def)
{
if (!key_cache_hash.hash.records)
return dflt_key_cache;
return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
return def;
return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length,
(void*) def);
}
@ -361,3 +102,5 @@ void multi_key_cache_change(KEY_CACHE *old_data,
{
safe_hash_change(&key_cache_hash, (uchar*) old_data, (uchar*) new_data);
}

View File

@ -122,6 +122,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
if (org_file >= 0 && file < 0)
{
int tmp=my_errno;
close(org_file);
(void) my_delete(to, MYF(MY_WME | ME_NOINPUT));
my_errno=tmp;
}

View File

@ -17,11 +17,10 @@
#include <my_pthread.h>
#ifndef HAVE_INLINE
/*
the following will cause all inline functions to be instantiated
*/
/* the following will cause all inline functions to be instantiated */
#define HAVE_INLINE
#define static extern
#undef STATIC_INLINE
#define STATIC_INLINE extern
#endif
#include <my_atomic.h>
@ -35,7 +34,7 @@
*/
int my_atomic_initialize()
{
DBUG_ASSERT(sizeof(intptr) == sizeof(void *));
compile_time_assert(sizeof(intptr) == sizeof(void *));
/* currently the only thing worth checking is SMP/UP issue */
#ifdef MY_ATOMIC_MODE_DUMMY
return my_getncpus() == 1 ? MY_ATOMIC_OK : MY_ATOMIC_NOT_1CPU;

View File

@ -13,23 +13,18 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Some useful bit functions */
#include <my_global.h>
#include "mysys_priv.h"
#ifndef HAVE_INLINE
/* the following will cause all inline functions to be instantiated */
#define HAVE_INLINE
#undef STATIC_INLINE
#define STATIC_INLINE extern
#endif
/*
Find smallest X in 2^X >= value
This can be used to divide a number with value by doing a shift instead
*/
#include <my_bit.h>
uint my_bit_log2(ulong value)
{
uint bit;
for (bit=0 ; value > 1 ; value>>=1, bit++) ;
return bit;
}
static char nbits[256] = {
const char _my_bits_nbits[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
@ -48,60 +43,29 @@ static char nbits[256] = {
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
};
uint my_count_bits(ulonglong v)
{
#if SIZEOF_LONG_LONG > 4
/* The following code is a bit faster on 16 bit machines than if we would
only shift v */
ulong v2=(ulong) (v >> 32);
return (uint) (uchar) (nbits[(uchar) v] +
nbits[(uchar) (v >> 8)] +
nbits[(uchar) (v >> 16)] +
nbits[(uchar) (v >> 24)] +
nbits[(uchar) (v2)] +
nbits[(uchar) (v2 >> 8)] +
nbits[(uchar) (v2 >> 16)] +
nbits[(uchar) (v2 >> 24)]);
#else
return (uint) (uchar) (nbits[(uchar) v] +
nbits[(uchar) (v >> 8)] +
nbits[(uchar) (v >> 16)] +
nbits[(uchar) (v >> 24)]);
#endif
}
uint my_count_bits_ushort(ushort v)
{
return nbits[v];
}
/*
Next highest power of two
SYNOPSIS
my_round_up_to_next_power()
v Value to check
RETURN
Next or equal power of 2
Note: 0 will return 0
NOTES
Algorithm by Sean Anderson, according to:
http://graphics.stanford.edu/~seander/bithacks.html
(Orignal code public domain)
Comments shows how this works with 01100000000000000000000000001011
perl -e 'print map{", 0x".unpack H2,pack B8,unpack b8,chr$_}(0..255)'
*/
const uchar _my_bits_reverse_table[256]={
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30,
0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98,
0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64,
0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC,
0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02,
0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2,
0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A,
0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E,
0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81,
0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71,
0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15,
0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD,
0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43,
0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B,
0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97,
0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F,
0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
uint32 my_round_up_to_next_power(uint32 v)
{
v--; /* 01100000000000000000000000001010 */
v|= v >> 1; /* 01110000000000000000000000001111 */
v|= v >> 2; /* 01111100000000000000000000001111 */
v|= v >> 4; /* 01111111110000000000000000001111 */
v|= v >> 8; /* 01111111111111111100000000001111 */
v|= v >> 16; /* 01111111111111111111111111111111 */
return v+1; /* 10000000000000000000000000000000 */
}

View File

@ -38,6 +38,7 @@
#include "mysys_priv.h"
#include <my_bitmap.h>
#include <m_string.h>
#include <my_bit.h>
void create_last_word_mask(MY_BITMAP *map)
{

View File

@ -181,8 +181,9 @@ int packfrm(uchar *data, size_t len,
if (my_compress((uchar*)data, &org_len, &comp_len))
goto err;
DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", (ulong) org_len, (ulong) comp_len));
DBUG_DUMP("compressed", data, org_len);
DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", (ulong) org_len,
(ulong) comp_len));
DBUG_DUMP("compressed", (char*)data, org_len);
error= 2;
blob_len= BLOB_HEADER + org_len;

View File

@ -52,6 +52,13 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
fd = open(FileName, access_flags);
#endif
if ((MyFlags & MY_SYNC_DIR) && (fd >=0) &&
my_sync_dir_by_file(FileName, MyFlags))
{
my_close(fd, MyFlags);
fd= -1;
}
DBUG_RETURN(my_register_filename(fd, FileName, FILE_BY_CREATE,
EE_CANTCREATEFILE, MyFlags));
} /* my_create */

View File

@ -29,6 +29,9 @@ int my_delete(const char *name, myf MyFlags)
my_error(EE_DELETE,MYF(ME_BELL+ME_WAITTANG+(MyFlags & ME_NOINPUT)),
name,errno);
}
else if ((MyFlags & MY_SYNC_DIR) &&
my_sync_dir_by_file(name, MyFlags))
err= -1;
DBUG_RETURN(err);
} /* my_delete */

View File

@ -84,11 +84,6 @@ int my_error(int nr, myf MyFlags, ...)
if (nr <= meh_p->meh_last)
break;
#ifdef SHARED_LIBRARY
if ((meh_p == &my_errmsgs_globerrs) && ! globerrs[0])
init_glob_errs();
#endif
/* get the error message string. Default, if NULL or empty string (""). */
if (! (format= (meh_p && (nr >= meh_p->meh_first)) ?
meh_p->meh_errmsgs[nr - meh_p->meh_first] : NULL) || ! *format)

View File

@ -16,9 +16,12 @@
MA 02111-1307, USA */
#include <my_global.h>
#include "my_handler.h"
#include <m_ctype.h>
#include <my_base.h>
#include <my_handler.h>
#include <my_sys.h>
int mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
int ha_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
uchar *b, uint b_length, my_bool part_key,
my_bool skip_end_space)
{
@ -174,7 +177,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
next_key_length=key_length-b_length-pack_length;
if (piks &&
(flag=mi_compare_text(keyseg->charset,a,a_length,b,b_length,
(flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
(my_bool) ((nextflag & SEARCH_PREFIX) &&
next_key_length <= 0),
(my_bool)!(nextflag & SEARCH_PREFIX))))
@ -187,7 +190,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
{
uint length=(uint) (end-a), a_length=length, b_length=length;
if (piks &&
(flag= mi_compare_text(keyseg->charset, a, a_length, b, b_length,
(flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
(my_bool) ((nextflag & SEARCH_PREFIX) &&
next_key_length <= 0),
(my_bool)!(nextflag & SEARCH_PREFIX))))
@ -235,7 +238,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
next_key_length=key_length-b_length-pack_length;
if (piks &&
(flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length,
(flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
(my_bool) ((nextflag & SEARCH_PREFIX) &&
next_key_length <= 0),
(my_bool) ((nextflag & (SEARCH_FIND |
@ -482,12 +485,15 @@ end:
DESCRIPTION
Find the first NULL value in index-suffix values tuple.
TODO Consider optimizing this fuction or its use so we don't search for
NULL values in completely NOT NULL index suffixes.
TODO
Consider optimizing this function or its use so we don't search for
NULL values in completely NOT NULL index suffixes.
RETURN
First key part that has NULL as value in values tuple, or the last key part
(with keyseg->type==HA_TYPE_END) if values tuple doesn't contain NULLs.
First key part that has NULL as value in values tuple, or the last key
part (with keyseg->type==HA_TYPE_END) if values tuple doesn't contain
NULLs.
*/
HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
@ -557,3 +563,69 @@ HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
}
return keyseg;
}
/*
Errors a handler can give you
*/
static const char *handler_error_messages[]=
{
"Didn't find key on read or update",
"Duplicate key on write or update",
"Undefined handler error 122",
"Someone has changed the row since it was read (while the table was locked to prevent it)",
"Wrong index given to function",
"Undefined handler error 125",
"Index file is crashed",
"Record file is crashed",
"Out of memory in engine",
"Undefined handler error 129",
"Incorrect file format",
"Command not supported by database",
"Old database file",
"No record read before update",
"Record was already deleted (or record file crashed)",
"No more room in record file",
"No more room in index file",
"No more records (read after end of file)",
"Unsupported extension used for table",
"Too big row",
"Wrong create options",
"Duplicate unique key or constraint on write or update",
"Unknown character set used in table",
"Conflicting table definitions in sub-tables of MERGE table",
"Table is crashed and last repair failed",
"Table was marked as crashed and should be repaired",
"Lock timed out; Retry transaction",
"Lock table is full; Restart program with a larger locktable",
"Updates are not allowed under a read only transactions",
"Lock deadlock; Retry transaction",
"Foreign key constraint is incorrectly formed",
"Cannot add a child row",
"Cannot delete a parent row",
"Unknown handler error"
};
/*
Register handler error messages for usage with my_error()
NOTES
This is safe to call multiple times as my_error_register()
will ignore calls to register already registered error numbers.
*/
void my_handler_error_register(void)
{
my_error_register(handler_error_messages, HA_ERR_FIRST,
HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
}
void my_handler_error_unregister(void)
{
my_error_unregister(HA_ERR_FIRST,
HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
}

View File

@ -43,6 +43,7 @@ static void netware_init();
my_bool my_init_done= 0;
uint mysys_usage_id= 0; /* Incremented for each my_init() */
ulong my_thread_stack_size= 65536;
static ulong atoi_octal(const char *str)
{
@ -76,6 +77,7 @@ my_bool my_init(void)
mysys_usage_id++;
my_umask= 0660; /* Default umask for new files */
my_umask_dir= 0700; /* Default umask for new directories */
init_glob_errs();
#if defined(THREAD) && defined(SAFE_MUTEX)
safe_mutex_global_init(); /* Must be called early */
#endif

View File

@ -71,6 +71,7 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
#else
fd = open((char *) FileName, Flags);
#endif
DBUG_RETURN(my_register_filename(fd, FileName, FILE_BY_OPEN,
EE_FILENOTFOUND, MyFlags));
} /* my_open */
@ -124,61 +125,66 @@ int my_close(File fd, myf MyFlags)
SYNOPSIS
my_register_filename()
fd
FileName
type_file_type
fd File number opened, -1 if error on open
FileName File name
type_file_type How file was created
error_message_number Error message number if caller got error (fd == -1)
MyFlags Flags for my_close()
RETURN
-1 error
# Filenumber
*/
File my_register_filename(File fd, const char *FileName, enum file_type
type_of_file, uint error_message_number, myf MyFlags)
{
DBUG_ENTER("my_register_filename");
if ((int) fd >= 0)
{
if ((uint) fd >= my_file_limit)
{
#if defined(THREAD) && !defined(HAVE_PREAD)
(void) my_close(fd,MyFlags);
my_errno=EMFILE;
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
my_error(EE_OUT_OF_FILERESOURCES, MYF(ME_BELL+ME_WAITTANG),
FileName, my_errno);
return(-1);
#endif
my_errno= EMFILE;
#else
thread_safe_increment(my_file_opened,&THR_LOCK_open);
return(fd); /* safeguard */
}
pthread_mutex_lock(&THR_LOCK_open);
if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
{
my_file_opened++;
my_file_total_opened++;
my_file_info[fd].type = type_of_file;
#if defined(THREAD) && !defined(HAVE_PREAD)
pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST);
DBUG_RETURN(fd); /* safeguard */
#endif
pthread_mutex_unlock(&THR_LOCK_open);
DBUG_PRINT("exit",("fd: %d",fd));
return(fd);
}
pthread_mutex_unlock(&THR_LOCK_open);
else
{
pthread_mutex_lock(&THR_LOCK_open);
if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
{
my_file_opened++;
my_file_total_opened++;
my_file_info[fd].type = type_of_file;
#if defined(THREAD) && !defined(HAVE_PREAD)
pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST);
#endif
pthread_mutex_unlock(&THR_LOCK_open);
DBUG_PRINT("exit",("fd: %d",fd));
DBUG_RETURN(fd);
}
pthread_mutex_unlock(&THR_LOCK_open);
my_errno= ENOMEM;
}
(void) my_close(fd, MyFlags);
my_errno=ENOMEM;
}
else
my_errno=errno;
DBUG_PRINT("error",("Got error %d on open",my_errno));
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) {
if (my_errno == EMFILE) {
DBUG_PRINT("error",("print err: %d",EE_OUT_OF_FILERESOURCES));
my_error(EE_OUT_OF_FILERESOURCES, MYF(ME_BELL+ME_WAITTANG),
FileName, my_errno);
} else {
DBUG_PRINT("error",("print err: %d",error_message_number));
my_error(error_message_number, MYF(ME_BELL+ME_WAITTANG),
FileName, my_errno);
}
my_errno= errno;
DBUG_PRINT("error",("Got error %d on open", my_errno));
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
{
if (my_errno == EMFILE)
error_message_number= EE_OUT_OF_FILERESOURCES;
DBUG_PRINT("error",("print err: %d",error_message_number));
my_error(error_message_number, MYF(ME_BELL+ME_WAITTANG),
FileName, my_errno);
}
return(fd);
DBUG_RETURN(-1);
}
#ifdef __WIN__

View File

@ -63,12 +63,12 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
#else
if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count)))
my_errno= errno;
my_errno= errno ? errno : -1;
#endif
if (error || readbytes != Count)
{
DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
(int) readbytes, (uint) Count,Filedes,my_errno));
(int) readbytes, (uint) Count,Filedes,my_errno));
#ifdef THREAD
if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
{
@ -115,7 +115,7 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
RETURN
(size_t) -1 Error
# Number of bytes read
*/
*/
size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
my_off_t offset, myf MyFlags)

View File

@ -22,6 +22,16 @@
/* My memory re allocator */
/**
@brief wrapper around realloc()
@param oldpoint pointer to currently allocated area
@param size new size requested, must be >0
@param my_flags flags
@note if size==0 realloc() may return NULL; my_realloc() treats this as an
error which is not the intention of realloc()
*/
void* my_realloc(void* oldpoint, size_t size, myf my_flags)
{
void *point;
@ -29,6 +39,7 @@ void* my_realloc(void* oldpoint, size_t size, myf my_flags)
DBUG_PRINT("my",("ptr: 0x%lx size: %lu my_flags: %d", (long) oldpoint,
(ulong) size, my_flags));
DBUG_ASSERT(size > 0);
if (!oldpoint && (my_flags & MY_ALLOW_ZERO_PTR))
DBUG_RETURN(my_malloc(size,my_flags));
#ifdef USE_HALLOC

View File

@ -16,8 +16,9 @@
#include "mysys_priv.h"
#include <my_dir.h>
#include "mysys_err.h"
#include "m_string.h"
#undef my_rename
/* On unix rename deletes to file if it exists */
int my_rename(const char *from, const char *to, myf MyFlags)
@ -60,5 +61,19 @@ int my_rename(const char *from, const char *to, myf MyFlags)
if (MyFlags & (MY_FAE+MY_WME))
my_error(EE_LINK, MYF(ME_BELL+ME_WAITTANG),from,to,my_errno);
}
else if (MyFlags & MY_SYNC_DIR)
{
#ifdef NEED_EXPLICIT_SYNC_DIR
/* do only the needed amount of syncs: */
char dir_from[FN_REFLEN], dir_to[FN_REFLEN];
size_t dir_from_length, dir_to_length;
dirname_part(dir_from, from, &dir_from_length);
dirname_part(dir_to, to, &dir_to_length);
if (my_sync_dir(dir_from, MyFlags) ||
(strcmp(dir_from, dir_to) &&
my_sync_dir(dir_to, MyFlags)))
error= -1;
#endif
}
DBUG_RETURN(error);
} /* my_rename */

297
mysys/my_safehash.c Normal file
View File

@ -0,0 +1,297 @@
/* Copyright (C) 2003-2007 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Handling of multiple key caches
The idea is to have a thread safe hash on the table name,
with a default key cache value that is returned if the table name is not in
the cache.
*/
#include "mysys_priv.h"
#include <m_string.h>
#include "my_safehash.h"
/*****************************************************************************
General functions to handle SAFE_HASH objects.
A SAFE_HASH object is used to store the hash, the mutex and default value
needed by the rest of the key cache code.
This is a separate struct to make it easy to later reuse the code for other
purposes
All entries are linked in a list to allow us to traverse all elements
and delete selected ones. (HASH doesn't allow any easy ways to do this).
*****************************************************************************/
/*
Free a SAFE_HASH_ENTRY
SYNOPSIS
safe_hash_entry_free()
entry The entry which should be freed
NOTE
This function is called by the hash object on delete
*/
static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
{
DBUG_ENTER("safe_hash_entry_free");
my_free((uchar*) entry, MYF(0));
DBUG_VOID_RETURN;
}
/*
Get key and length for a SAFE_HASH_ENTRY
SYNOPSIS
safe_hash_entry_get()
entry The entry for which the key should be returned
length Length of the key
RETURN
# reference on the key
*/
static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length= entry->length;
return (uchar*) entry->key;
}
/*
Init a SAFE_HASH object
SYNOPSIS
safe_hash_init()
hash safe_hash handler
elements Expected max number of elements
default_value default value
NOTES
In case of error we set hash->default_value to 0 to allow one to call
safe_hash_free on an object that couldn't be initialized.
RETURN
0 OK
1 error
*/
my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
uchar *default_value)
{
DBUG_ENTER("safe_hash_init");
if (hash_init(&hash->hash, &my_charset_bin, elements,
0, 0, (hash_get_key) safe_hash_entry_get,
(void (*)(void*)) safe_hash_entry_free, 0))
{
hash->default_value= 0;
DBUG_RETURN(1);
}
my_rwlock_init(&hash->mutex, 0);
hash->default_value= default_value;
hash->root= 0;
DBUG_RETURN(0);
}
/*
Free a SAFE_HASH object
SYNOPSIS
safe_hash_free()
hash Hash handle
NOTES
This is safe to call on any object that has been sent to safe_hash_init()
*/
void safe_hash_free(SAFE_HASH *hash)
{
/*
Test if safe_hash_init succeeded. This will also guard us against multiple
free calls.
*/
if (hash->default_value)
{
hash_free(&hash->hash);
rwlock_destroy(&hash->mutex);
hash->default_value=0;
}
}
/*
Return the value stored for a key or default value if no key
SYNOPSIS
safe_hash_search()
hash Hash handle
key key (path to table etc..)
length Length of key
def Default value of data
RETURN
# data associated with the key of default value if data was not found
*/
uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length,
uchar *def)
{
uchar *result;
DBUG_ENTER("safe_hash_search");
rw_rdlock(&hash->mutex);
result= hash_search(&hash->hash, key, length);
rw_unlock(&hash->mutex);
if (!result)
result= def;
else
result= ((SAFE_HASH_ENTRY*) result)->data;
DBUG_PRINT("exit",("data: 0x%lx", (long) result));
DBUG_RETURN(result);
}
/*
Associate a key with some data
SYNOPSIS
safe_hash_set()
hash Hash handle
key key (path to table etc..)
length Length of key
data data to to associate with the data
NOTES
This can be used both to insert a new entry and change an existing
entry.
If one associates a key with the default key cache, the key is deleted
RETURN
0 OK
1 error (Can only be EOM). In this case my_message() is called.
*/
my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
uchar *data)
{
SAFE_HASH_ENTRY *entry;
my_bool error= 0;
DBUG_ENTER("safe_hash_set");
DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data));
rw_wrlock(&hash->mutex);
entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
if (data == hash->default_value)
{
/*
The key is to be associated with the default entry. In this case
we can just delete the entry (if it existed) from the hash as a
search will return the default entry
*/
if (!entry) /* nothing to do */
goto end;
/* unlink entry from list */
if ((*entry->prev= entry->next))
entry->next->prev= entry->prev;
hash_delete(&hash->hash, (uchar*) entry);
goto end;
}
if (entry)
{
/* Entry existed; Just change the pointer to point at the new data */
entry->data= data;
}
else
{
if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
MYF(MY_WME))))
{
error= 1;
goto end;
}
entry->key= (uchar*) (entry +1);
memcpy((char*) entry->key, (char*) key, length);
entry->length= length;
entry->data= data;
/* Link entry to list */
if ((entry->next= hash->root))
entry->next->prev= &entry->next;
entry->prev= &hash->root;
hash->root= entry;
if (my_hash_insert(&hash->hash, (uchar*) entry))
{
/* This can only happen if hash got out of memory */
my_free((char*) entry, MYF(0));
error= 1;
goto end;
}
}
end:
rw_unlock(&hash->mutex);
DBUG_RETURN(error);
}
/*
Change all entries with one data value to another data value
SYNOPSIS
safe_hash_change()
hash Hash handle
old_data Old data
new_data Change all 'old_data' to this
NOTES
We use the linked list to traverse all elements in the hash as
this allows us to delete elements in the case where 'new_data' is the
default value.
*/
void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
{
SAFE_HASH_ENTRY *entry, *next;
DBUG_ENTER("safe_hash_change");
rw_wrlock(&hash->mutex);
for (entry= hash->root ; entry ; entry= next)
{
next= entry->next;
if (entry->data == old_data)
{
if (new_data == hash->default_value)
{
if ((*entry->prev= entry->next))
entry->next->prev= entry->prev;
hash_delete(&hash->hash, (uchar*) entry);
}
else
entry->data= new_data;
}
}
rw_unlock(&hash->mutex);
DBUG_VOID_RETURN;
}

58
mysys/my_safehash.h Normal file
View File

@ -0,0 +1,58 @@
/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Handling of multiple key caches
The idea is to have a thread safe hash on the table name,
with a default key cache value that is returned if the table name is not in
the cache.
*/
#include <hash.h>
/*
Struct to store a key and pointer to object
*/
typedef struct st_safe_hash_entry
{
uchar *key;
uint length;
uchar *data;
struct st_safe_hash_entry *next, **prev;
} SAFE_HASH_ENTRY;
typedef struct st_safe_hash_with_default
{
#ifdef THREAD
rw_lock_t mutex;
#endif
HASH hash;
uchar *default_value;
SAFE_HASH_ENTRY *root;
} SAFE_HASH;
my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
uchar *default_value);
void safe_hash_free(SAFE_HASH *hash);
uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length,
uchar *def);
my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
uchar *data);
void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data);

View File

@ -84,6 +84,8 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags)
if (MyFlags & MY_WME)
my_error(EE_CANT_SYMLINK, MYF(0), linkname, content, errno);
}
else if ((MyFlags & MY_SYNC_DIR) && my_sync_dir_by_file(linkname, MyFlags))
result= -1;
DBUG_RETURN(result);
#endif /* HAVE_READLINK */
}

View File

@ -48,6 +48,16 @@ int my_sync(File fd, myf my_flags)
do
{
#if defined(F_FULLFSYNC)
/*
In Mac OS X >= 10.3 this call is safer than fsync() (it forces the
disk's cache and guarantees ordered writes).
*/
if (!(res= fcntl(fd, F_FULLFSYNC, 0)))
break; /* ok */
/* Some file systems don't support F_FULLFSYNC and fail above: */
DBUG_PRINT("info",("fcntl(F_FULLFSYNC) failed, falling back"));
#endif
#if defined(HAVE_FDATASYNC)
res= fdatasync(fd);
#elif defined(HAVE_FSYNC)
@ -55,6 +65,7 @@ int my_sync(File fd, myf my_flags)
#elif defined(__WIN__)
res= _commit(fd);
#else
#error Cannot find a way to sync a file, durability in danger
res= 0; /* No sync (strange OS) */
#endif
} while (res == -1 && errno == EINTR);
@ -66,10 +77,79 @@ int my_sync(File fd, myf my_flags)
my_errno= -1; /* Unknown error */
if ((my_flags & MY_IGNORE_BADFD) &&
(er == EBADF || er == EINVAL || er == EROFS))
{
DBUG_PRINT("info", ("ignoring errno %d", er));
res= 0;
}
else if (my_flags & MY_WME)
my_error(EE_SYNC, MYF(ME_BELL+ME_WAITTANG), my_filename(fd), my_errno);
}
DBUG_RETURN(res);
} /* my_sync */
static const char cur_dir_name[]= {FN_CURLIB, 0};
/*
Force directory information to disk.
SYNOPSIS
my_sync_dir()
dir_name the name of the directory
my_flags flags (MY_WME etc)
RETURN
0 if ok, !=0 if error
*/
int my_sync_dir(const char *dir_name, myf my_flags)
{
#ifdef NEED_EXPLICIT_SYNC_DIR
DBUG_ENTER("my_sync_dir");
DBUG_PRINT("my",("Dir: '%s' my_flags: %d", dir_name, my_flags));
File dir_fd;
int res= 0;
const char *correct_dir_name;
/* Sometimes the path does not contain an explicit directory */
correct_dir_name= (dir_name[0] == 0) ? cur_dir_name : dir_name;
/*
Syncing a dir may give EINVAL on tmpfs on Linux, which is ok.
EIO on the other hand is very important. Hence MY_IGNORE_BADFD.
*/
if ((dir_fd= my_open(correct_dir_name, O_RDONLY, MYF(my_flags))) >= 0)
{
if (my_sync(dir_fd, MYF(my_flags | MY_IGNORE_BADFD)))
res= 2;
if (my_close(dir_fd, MYF(my_flags)))
res= 3;
}
else
res= 1;
DBUG_RETURN(res);
#else
return 0;
#endif
}
/*
Force directory information to disk.
SYNOPSIS
my_sync_dir_by_file()
file_name the name of a file in the directory
my_flags flags (MY_WME etc)
RETURN
0 if ok, !=0 if error
*/
int my_sync_dir_by_file(const char *file_name, myf my_flags)
{
#ifdef NEED_EXPLICIT_SYNC_DIR
char dir_name[FN_REFLEN];
size_t dir_name_length;
dirname_part(dir_name, file_name, &dir_name_length);
return my_sync_dir(dir_name, my_flags);
#else
return 0;
#endif
}

View File

@ -430,6 +430,29 @@ void TERMINATE(FILE *file, uint flag)
}
/*
Report where a piece of memory was allocated
This is usefull to call from withing a debugger
*/
void sf_malloc_report_allocated(void *memory)
{
struct st_irem *irem;
for (irem= sf_malloc_root ; irem ; irem=irem->next)
{
char *data= (((char*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) +
sf_malloc_prehunc);
if (data <= (char*) memory && (char*) memory <= data + irem->datasize)
{
printf("%u bytes at 0x%lx, allocated at line %u in '%s'\n",
irem->datasize, (long) data, irem->linenum, irem->filename);
break;
}
}
}
/* Returns 0 if chunk is ok */
static int _checkchunk(register struct st_irem *irem, const char *filename,

Some files were not shown because too many files have changed in this diff Show More