Commit 8f3b5ebd authored by Vadim Tkachenko's avatar Vadim Tkachenko

Sync with patches commit rev 8

parent bf05180b
......@@ -131,7 +131,7 @@ noinst_HEADERS= include/btr0btr.h include/btr0btr.ic \
include/ut0list.ic include/ut0wqueue.h \
include/ha_prototypes.h handler/ha_innodb.h \
include/handler0alter.h \
handler/i_s.h
handler/i_s.h handler/innodb_patch_info.h
EXTRA_LIBRARIES= libinnobase.a
noinst_LIBRARIES= @plugin_innobase_static_target@
......
......@@ -651,7 +651,7 @@ noinst_HEADERS = include/btr0btr.h include/btr0btr.ic \
include/ut0list.ic include/ut0wqueue.h \
include/ha_prototypes.h handler/ha_innodb.h \
include/handler0alter.h \
handler/i_s.h
handler/i_s.h handler/innodb_patch_info.h
EXTRA_LIBRARIES = libinnobase.a
noinst_LIBRARIES = @plugin_innobase_static_target@
......
......@@ -3596,12 +3596,14 @@ buf_print_io(
fprintf(file,
"Buffer pool size %lu\n"
"Buffer pool size, bytes %lu\n"
"Free buffers %lu\n"
"Database pages %lu\n"
"Modified db pages %lu\n"
"Pending reads %lu\n"
"Pending writes: LRU %lu, flush list %lu, single page %lu\n",
(ulong) size,
(ulong) size * UNIV_PAGE_SIZE,
(ulong) UT_LIST_GET_LEN(buf_pool->free),
(ulong) UT_LIST_GET_LEN(buf_pool->LRU),
(ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
......
......@@ -4816,3 +4816,30 @@ fil_page_get_type(
return(mach_read_from_2(page + FIL_PAGE_TYPE));
}
/*************************************************************************
Return local hash table informations. */
ulint
fil_system_hash_cells(void)
/*=======================*/
{
if (fil_system) {
return (fil_system->spaces->n_cells
+ fil_system->name_hash->n_cells);
} else {
return 0;
}
}
ulint
fil_system_hash_nodes(void)
/*=======================*/
{
if (fil_system) {
return (UT_LIST_GET_LEN(fil_system->space_list)
* (sizeof(fil_space_t) + MEM_BLOCK_HEADER_SIZE));
} else {
return 0;
}
}
......@@ -9409,6 +9409,16 @@ static MYSQL_SYSVAR_BOOL(locks_unsafe_for_binlog, innobase_locks_unsafe_for_binl
"Force InnoDB to not use next-key locking, to use only row-level locking.",
NULL, NULL, FALSE);
static MYSQL_SYSVAR_ULONG(show_verbose_locks, srv_show_verbose_locks,
PLUGIN_VAR_OPCMDARG,
"Whether to show records locked in SHOW INNODB STATUS.",
NULL, NULL, 0, 0, 1, 0);
static MYSQL_SYSVAR_ULONG(show_locks_held, srv_show_locks_held,
PLUGIN_VAR_RQCMDARG,
"Number of locks held to print for each InnoDB transaction in SHOW INNODB STATUS.",
NULL, NULL, 10, 0, 1000, 0);
#ifdef UNIV_LOG_ARCHIVE
static MYSQL_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
......@@ -9559,7 +9569,7 @@ static MYSQL_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
static MYSQL_SYSVAR_STR(version, innodb_version_str,
PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
"InnoDB version", NULL, NULL, INNODB_VERSION_STR);
"Percona-InnoDB-plugin version", NULL, NULL, INNODB_VERSION_STR);
static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity,
PLUGIN_VAR_RQCMDARG,
......@@ -9573,7 +9583,7 @@ static MYSQL_SYSVAR_ULONG(read_ahead, srv_read_ahead,
static MYSQL_SYSVAR_ULONG(adaptive_checkpoint, srv_adaptive_checkpoint,
PLUGIN_VAR_RQCMDARG,
"Enable/Diasable flushing along modified age 0:disable 1:enable",
"Enable/Disable flushing along modified age 0:disable 1:enable",
NULL, NULL, 0, 0, 1, 0);
static MYSQL_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
......@@ -9631,6 +9641,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(thread_concurrency),
MYSQL_SYSVAR(thread_sleep_delay),
MYSQL_SYSVAR(autoinc_lock_mode),
MYSQL_SYSVAR(show_verbose_locks),
MYSQL_SYSVAR(show_locks_held),
MYSQL_SYSVAR(version),
MYSQL_SYSVAR(io_capacity),
MYSQL_SYSVAR(read_ahead),
......@@ -9823,7 +9835,8 @@ i_s_innodb_lock_waits,
i_s_innodb_cmp,
i_s_innodb_cmp_reset,
i_s_innodb_cmpmem,
i_s_innodb_cmpmem_reset
i_s_innodb_cmpmem_reset,
i_s_innodb_patches
mysql_declare_plugin_end;
#ifdef UNIV_COMPILE_TEST_FUNCS
......
......@@ -15,6 +15,7 @@ Created July 18, 2007 Vasil Dimov
#include <mysys_err.h>
#include <my_sys.h>
#include "i_s.h"
#include "innodb_patch_info.h"
#include <mysql/plugin.h>
extern "C" {
......@@ -199,6 +200,188 @@ field_store_ulint(
return(ret);
}
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_patches */
static ST_FIELD_INFO innodb_patches_fields_info[] =
{
#define IDX_PATCH_NAME 0
{STRUCT_FLD(field_name, "name"),
STRUCT_FLD(field_length, 255),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_PATCH_DESCR 1
{STRUCT_FLD(field_name, "description"),
STRUCT_FLD(field_length, 255),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_PATCH_VER 2
{STRUCT_FLD(field_name, "version"),
STRUCT_FLD(field_length, 10),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_PATCH_AUTHOR 3
{STRUCT_FLD(field_name, "author"),
STRUCT_FLD(field_length, 50),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_PATCH_LICENCE 4
{STRUCT_FLD(field_name, "licence"),
STRUCT_FLD(field_length, 50),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
#define IDX_PATCH_COMMENT 5
{STRUCT_FLD(field_name, "comment"),
STRUCT_FLD(field_length, 100),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
END_OF_ST_FIELD_INFO
};
static struct st_mysql_information_schema i_s_info =
{
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
/***********************************************************************
Fill the dynamic table information_schema.innodb_patches */
static
int
innodb_patches_fill(
/*=============*/
/* out: 0 on success, 1 on failure */
THD* thd, /* in: thread */
TABLE_LIST* tables, /* in/out: tables to fill */
COND* cond) /* in: condition (ignored) */
{
TABLE* table = (TABLE *) tables->table;
int status = 0;
int i;
Field** fields;
DBUG_ENTER("innodb_patches_fill");
fields = table->field;
/* deny access to non-superusers */
if (check_global_access(thd, PROCESS_ACL)) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
for (i = 0; innodb_patches[i].file; i++) {
field_store_string(fields[0],innodb_patches[i].file);
field_store_string(fields[1],innodb_patches[i].name);
field_store_string(fields[2],innodb_patches[i].version);
field_store_string(fields[3],innodb_patches[i].author);
field_store_string(fields[4],innodb_patches[i].license);
field_store_string(fields[5],innodb_patches[i].comment);
if (schema_table_store_record(thd, table)) {
status = 1;
break;
}
}
DBUG_RETURN(status);
}
/***********************************************************************
Bind the dynamic table information_schema.innodb_patches. */
static
int
innodb_patches_init(
/*=========*/
/* out: 0 on success */
void* p) /* in/out: table schema object */
{
DBUG_ENTER("innodb_patches_init");
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
schema->fields_info = innodb_patches_fields_info;
schema->fill_table = innodb_patches_fill;
DBUG_RETURN(0);
}
UNIV_INTERN struct st_mysql_plugin i_s_innodb_patches =
{
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
/* int */
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
/* pointer to type-specific plugin descriptor */
/* void* */
STRUCT_FLD(info, &i_s_info),
/* plugin name */
/* const char* */
STRUCT_FLD(name, "INNODB_PATCHES"),
/* plugin author (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(author, "Percona"),
/* general descriptive text (for SHOW PLUGINS) */
/* const char* */
STRUCT_FLD(descr, "Patches applied to InnoDB plugin"),
/* the plugin license (PLUGIN_LICENSE_XXX) */
/* int */
STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
/* the function to invoke when plugin is loaded */
/* int (*)(void*); */
STRUCT_FLD(init, innodb_patches_init),
/* the function to invoke when plugin is unloaded */
/* int (*)(void*); */
STRUCT_FLD(deinit, i_s_common_deinit),
/* plugin version (for SHOW PLUGINS) */
/* unsigned int */
STRUCT_FLD(version, INNODB_VERSION_SHORT),
/* struct st_mysql_show_var* */
STRUCT_FLD(status_vars, NULL),
/* struct st_mysql_sys_var** */
STRUCT_FLD(system_vars, NULL),
/* reserved for dependency checking */
/* void* */
STRUCT_FLD(__reserved1, NULL)
};
/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx */
static ST_FIELD_INFO innodb_trx_fields_info[] =
{
......@@ -383,10 +566,6 @@ innodb_trx_init(
DBUG_RETURN(0);
}
static struct st_mysql_information_schema i_s_info =
{
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
UNIV_INTERN struct st_mysql_plugin i_s_innodb_trx =
{
......
......@@ -16,5 +16,6 @@ extern struct st_mysql_plugin i_s_innodb_cmp;
extern struct st_mysql_plugin i_s_innodb_cmp_reset;
extern struct st_mysql_plugin i_s_innodb_cmpmem;
extern struct st_mysql_plugin i_s_innodb_cmpmem_reset;
extern struct st_mysql_plugin i_s_innodb_patches;
#endif /* i_s_h */
/* Copyright (C) 2002-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; version 2 of the License.
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 */
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
struct innodb_patch {
const char *file;
const char *name;
const char *version;
const char *author;
const char *license;
const char *comment;
}innodb_patches[] = {
{"innodb_show_patches.patch","I_S.INNODB_PATCHES","1.0","Percona","GPLv2",""},
{"innodb_show_status.patch","Fixes to SHOW INNODB STATUS","1.0","Percona","GPLv2","Memory information and lock info fixes"},
{"innodb_io_patches.patch","Patches to InnoDB IO","1.0","Percona","GPLv2",""},
{"innodb_rw_lock.patch","InnoDB RW-lock fixes","1.0","Percona","GPLv2","Useful for 8+ cores SMP systems"},
{NULL, NULL, NULL, NULL, NULL, NULL}
};
......@@ -696,6 +696,16 @@ fil_page_get_type(
return value not defined */
const byte* page); /* in: file page */
/*************************************************************************
Return local hash table informations. */
ulint
fil_system_hash_cells(void);
/*========================*/
ulint
fil_system_hash_nodes(void);
/*========================*/
typedef struct fil_space_struct fil_space_t;
......
......@@ -90,6 +90,9 @@ extern ulint srv_log_file_size;
extern ulint srv_log_buffer_size;
extern ulong srv_flush_log_at_trx_commit;
extern ulint srv_show_locks_held;
extern ulint srv_show_verbose_locks;
/* The sort order table of the MySQL latin1_swedish_ci character set
collation */
extern const byte* srv_latin1_ordering;
......
......@@ -328,7 +328,17 @@ rw_lock_get_x_lock_count(
Accessor functions for rw lock. */
UNIV_INLINE
ulint
rw_lock_get_waiters(
rw_lock_get_s_waiters(
/*==================*/
rw_lock_t* lock);
UNIV_INLINE
ulint
rw_lock_get_x_waiters(
/*==================*/
rw_lock_t* lock);
UNIV_INLINE
ulint
rw_lock_get_wx_waiters(
/*================*/
rw_lock_t* lock);
UNIV_INLINE
......@@ -412,6 +422,11 @@ rw_lock_debug_print(
rw_lock_debug_t* info); /* in: debug struct */
#endif /* UNIV_SYNC_DEBUG */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/* This value means NOT_LOCKED */
#define RW_LOCK_BIAS 0x00100000
#endif
/* NOTE! The structure appears here only for the compiler to know its size.
Do not use its fields directly! The structure used in the spin lock
implementation of a read-write lock. Several threads may have a shared lock
......@@ -421,9 +436,9 @@ blocked by readers, a writer may queue for the lock by setting the writer
field. Then no new readers are allowed in. */
struct rw_lock_struct {
os_event_t event; /* Used by sync0arr.c for thread queueing */
#ifdef __WIN__
/* Used by sync0arr.c for thread queueing */
os_event_t s_event; /* Used for s_lock */
os_event_t x_event; /* Used for x_lock */
os_event_t wait_ex_event; /* This windows specific event is
used by the thread which has set the
lock state to RW_LOCK_WAIT_EX. The
......@@ -431,30 +446,34 @@ struct rw_lock_struct {
thread will be the next one to proceed
once the current the event gets
signalled. See LEMMA 2 in sync0sync.c */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
volatile lint lock_word; /* Used by using atomic builtin */
#endif
ulint reader_count; /* Number of readers who have locked this
volatile ulint reader_count; /* Number of readers who have locked this
lock in the shared mode */
ulint writer; /* This field is set to RW_LOCK_EX if there
volatile ulint writer; /* This field is set to RW_LOCK_EX if there
is a writer owning the lock (in exclusive
mode), RW_LOCK_WAIT_EX if a writer is
queueing for the lock, and
RW_LOCK_NOT_LOCKED, otherwise. */
os_thread_id_t writer_thread;
volatile os_thread_id_t writer_thread;
/* Thread id of a possible writer thread */
ulint writer_count; /* Number of times the same thread has
volatile ulint writer_count; /* Number of times the same thread has
recursively locked the lock in the exclusive
mode */
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_t mutex; /* The mutex protecting rw_lock_struct */
#endif
ulint pass; /* Default value 0. This is set to some
value != 0 given by the caller of an x-lock
operation, if the x-lock is to be passed to
another thread to unlock (which happens in
asynchronous i/o). */
ulint waiters; /* This ulint is set to 1 if there are
waiters (readers or writers) in the global
wait array, waiting for this rw_lock.
Otherwise, == 0. */
volatile ulint s_waiters; /* 1: there are waiters (s_lock) */
volatile ulint x_waiters; /* 1: there are waiters (x_lock) */
volatile ulint wait_ex_waiters; /* 1: there are waiters (wait_ex) */
UT_LIST_NODE_T(rw_lock_t) list;
/* All allocated rw locks are put into a
list */
......@@ -467,7 +486,7 @@ struct rw_lock_struct {
const char* cfile_name;/* File name where lock created */
const char* last_s_file_name;/* File name where last s-locked */
const char* last_x_file_name;/* File name where last x-locked */
ibool writer_is_wait_ex;
volatile ibool writer_is_wait_ex;
/* This is TRUE if the writer field is
RW_LOCK_WAIT_EX; this field is located far
from the memory update hotspot fields which
......
......@@ -47,20 +47,52 @@ rw_lock_remove_debug_info(
Accessor functions for rw lock. */
UNIV_INLINE
ulint
rw_lock_get_waiters(
rw_lock_get_s_waiters(
/*================*/
rw_lock_t* lock)
{
return(lock->waiters);
return(lock->s_waiters);
}
UNIV_INLINE
ulint
rw_lock_get_x_waiters(
/*================*/
rw_lock_t* lock)
{
return(lock->x_waiters);
}
UNIV_INLINE
ulint
rw_lock_get_wx_waiters(
/*================*/
rw_lock_t* lock)
{
return(lock->wait_ex_waiters);
}
UNIV_INLINE
void
rw_lock_set_s_waiters(
rw_lock_t* lock,
ulint flag)
{
lock->s_waiters = flag;
}
UNIV_INLINE
void
rw_lock_set_waiters(
rw_lock_set_x_waiters(
rw_lock_t* lock,
ulint flag)
{
lock->x_waiters = flag;
}
UNIV_INLINE
void
rw_lock_set_wx_waiters(
/*================*/
rw_lock_t* lock,
ulint flag)
{
lock->waiters = flag;
lock->wait_ex_waiters = flag;
}
UNIV_INLINE
ulint
......@@ -68,7 +100,19 @@ rw_lock_get_writer(
/*===============*/
rw_lock_t* lock)
{
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if (lock->writer == RW_LOCK_NOT_LOCKED) {
return(RW_LOCK_NOT_LOCKED);
}
if (lock->writer_is_wait_ex) {
return(RW_LOCK_WAIT_EX);
} else {
return(RW_LOCK_EX);
}
#else
return(lock->writer);
#endif
}
UNIV_INLINE
void
......@@ -96,6 +140,7 @@ rw_lock_set_reader_count(
{
lock->reader_count = count;
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
UNIV_INLINE
mutex_t*
rw_lock_get_mutex(
......@@ -104,6 +149,7 @@ rw_lock_get_mutex(
{
return(&(lock->mutex));
}
#endif
/**********************************************************************
Returns the value of writer_count for the lock. Does not reserve the lock
......@@ -133,13 +179,27 @@ rw_lock_s_lock_low(
const char* file_name, /* in: file name where lock requested */
ulint line) /* in: line where requested */
{
#ifndef HAVE_GCC_ATOMIC_BUILTINS
ut_ad(mutex_own(rw_lock_get_mutex(lock)));
#endif
/* Check if the writer field is free */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if (UNIV_LIKELY(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED)) {
/* try s-lock */
if(__sync_sub_and_fetch(&(lock->lock_word),1) <= 0) {
/* fail */
__sync_fetch_and_add(&(lock->lock_word),1);
return(FALSE); /* locking did not succeed */
}
/* success */
__sync_fetch_and_add(&(lock->reader_count),1);
#else
if (UNIV_LIKELY(lock->writer == RW_LOCK_NOT_LOCKED)) {
/* Set the shared lock by incrementing the reader count */
lock->reader_count++;
#endif
#ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name,
......@@ -166,11 +226,15 @@ rw_lock_s_lock_direct(
const char* file_name, /* in: file name where requested */
ulint line) /* in: line where lock requested */
{
ut_ad(lock->writer == RW_LOCK_NOT_LOCKED);
ut_ad(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
ut_ad(rw_lock_get_reader_count(lock) == 0);
/* Set the shared lock by incrementing the reader count */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
__sync_fetch_and_add(&(lock->reader_count),1);
#else
lock->reader_count++;
#endif
lock->last_s_file_name = file_name;
lock->last_s_line = line;
......@@ -198,7 +262,11 @@ rw_lock_x_lock_direct(
rw_lock_set_writer(lock, RW_LOCK_EX);
lock->writer_thread = os_thread_get_curr_id();
#ifdef HAVE_GCC_ATOMIC_BUILTINS
__sync_fetch_and_add(&(lock->writer_count),1);
#else
lock->writer_count++;
#endif
lock->pass = 0;
lock->last_x_file_name = file_name;
......@@ -240,15 +308,21 @@ rw_lock_s_lock_func(
ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
#endif /* UNIV_SYNC_DEBUG */
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_enter(rw_lock_get_mutex(lock));
#endif
if (UNIV_LIKELY(rw_lock_s_lock_low(lock, pass, file_name, line))) {
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(rw_lock_get_mutex(lock));
#endif
return; /* Success */
} else {
/* Did not succeed, try spin wait */
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(rw_lock_get_mutex(lock));
#endif
rw_lock_s_lock_spin(lock, pass, file_name, line);
......@@ -271,11 +345,23 @@ rw_lock_s_lock_func_nowait(
{
ibool success = FALSE;
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) {
/* try s-lock */
if(__sync_sub_and_fetch(&(lock->lock_word),1) <= 0) {
/* fail */
__sync_fetch_and_add(&(lock->lock_word),1);
return(FALSE); /* locking did not succeed */
}
/* success */
__sync_fetch_and_add(&(lock->reader_count),1);
#else
mutex_enter(rw_lock_get_mutex(lock));
if (lock->writer == RW_LOCK_NOT_LOCKED) {
/* Set the shared lock by incrementing the reader count */
lock->reader_count++;
#endif
#ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name,
......@@ -288,7 +374,9 @@ rw_lock_s_lock_func_nowait(
success = TRUE;
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(rw_lock_get_mutex(lock));
#endif
return(success);
}
......@@ -308,6 +396,55 @@ rw_lock_x_lock_func_nowait(
{
ibool success = FALSE;
os_thread_id_t curr_thread = os_thread_get_curr_id();
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if ((lock->lock_word == RW_LOCK_BIAS)
&& rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) {
/* try x-lock */
if(__sync_sub_and_fetch(&(lock->lock_word),
RW_LOCK_BIAS) == 0) {
/* success */
/* try to lock writer */
if(__sync_lock_test_and_set(&(lock->writer),RW_LOCK_EX)
== RW_LOCK_NOT_LOCKED) {
/* success */
lock->writer_thread = curr_thread;
lock->pass = 0;
lock->writer_is_wait_ex = FALSE;
/* next function may work as memory barrier */
relock:
__sync_fetch_and_add(&(lock->writer_count),1);
#ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
#endif
lock->last_x_file_name = file_name;
lock->last_x_line = line;
ut_ad(rw_lock_validate(lock));
return(TRUE);
} else {
/* x-unlock */
__sync_fetch_and_add(&(lock->lock_word),
RW_LOCK_BIAS);
}
} else {
/* fail (x-lock) */
__sync_fetch_and_add(&(lock->lock_word),RW_LOCK_BIAS);
}
}
if (lock->pass == 0
&& os_thread_eq(lock->writer_thread, curr_thread)
&& rw_lock_get_writer(lock) == RW_LOCK_EX) {
goto relock;
}
ut_ad(rw_lock_validate(lock));
return(FALSE);
#else
mutex_enter(rw_lock_get_mutex(lock));
if (UNIV_UNLIKELY(rw_lock_get_reader_count(lock) != 0)) {
......@@ -338,6 +475,7 @@ relock:
ut_ad(rw_lock_validate(lock));
return(success);
#endif
}
/**********************************************************************
......@@ -353,16 +491,33 @@ rw_lock_s_unlock_func(
#endif
)
{
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_t* mutex = &(lock->mutex);
ibool sg = FALSE;
#endif
ibool x_sg = FALSE;
ibool wx_sg = FALSE;
#ifdef HAVE_GCC_ATOMIC_BUILTINS
ibool last = FALSE;
#endif
#ifndef HAVE_GCC_ATOMIC_BUILTINS
/* Acquire the mutex protecting the rw-lock fields */
mutex_enter(mutex);
#endif
/* Reset the shared lock by decrementing the reader count */
ut_a(lock->reader_count > 0);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/* unlock lock_word */
__sync_fetch_and_add(&(lock->lock_word),1);
if(__sync_sub_and_fetch(&(lock->reader_count),1) == 0) {
last = TRUE;
}
#else
lock->reader_count--;
#endif
#ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);
......@@ -371,20 +526,36 @@ rw_lock_s_unlock_func(
/* If there may be waiters and this was the last s-lock,
signal the object */
if (UNIV_UNLIKELY(lock->waiters)
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if (UNIV_UNLIKELY(last && lock->wait_ex_waiters)) {
#else
if (UNIV_UNLIKELY(lock->wait_ex_waiters)
&& lock->reader_count == 0) {
sg = TRUE;
#endif
wx_sg = TRUE;
rw_lock_set_waiters(lock, 0);
rw_lock_set_wx_waiters(lock, 0);
}
#ifdef HAVE_GCC_ATOMIC_BUILTINS
else if (UNIV_UNLIKELY(last && lock->x_waiters)) {
#else
else if (UNIV_UNLIKELY(lock->x_waiters)
&& lock->reader_count == 0) {
#endif
x_sg = TRUE;
rw_lock_set_x_waiters(lock, 0);
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(mutex);
#endif
if (UNIV_UNLIKELY(sg)) {
#ifdef __WIN__
if (UNIV_UNLIKELY(wx_sg)) {
os_event_set(lock->wait_ex_event);
#endif
os_event_set(lock->event);
sync_array_object_signalled(sync_primary_wait_array);
} else if (UNIV_UNLIKELY(x_sg)) {
os_event_set(lock->x_event);
sync_array_object_signalled(sync_primary_wait_array);
}
......@@ -408,13 +579,19 @@ rw_lock_s_unlock_direct(
ut_ad(lock->reader_count > 0);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
__sync_sub_and_fetch(&(lock->reader_count),1);
#else
lock->reader_count--;
#endif
#ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);
#endif
ut_ad(!lock->waiters);
ut_ad(!lock->s_waiters);
ut_ad(!lock->x_waiters);
ut_ad(!lock->wait_ex_waiters);
ut_ad(rw_lock_validate(lock));
#ifdef UNIV_SYNC_PERF_STAT
rw_s_exit_count++;
......@@ -434,41 +611,81 @@ rw_lock_x_unlock_func(
#endif
)
{
ibool sg = FALSE;
#ifdef HAVE_GCC_ATOMIC_BUILTINS
ibool last = FALSE;
#endif
ibool s_sg = FALSE;
ibool x_sg = FALSE;
#ifndef HAVE_GCC_ATOMIC_BUILTINS
/* Acquire the mutex protecting the rw-lock fields */
mutex_enter(&(lock->mutex));
#endif
/* Reset the exclusive lock if this thread no longer has an x-mode
lock */
ut_ad(lock->writer_count > 0);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if(__sync_sub_and_fetch(&(lock->writer_count),1) == 0) {
last = TRUE;
}
if (last) {
/* unlock lock_word */
__sync_fetch_and_add(&(lock->lock_word),RW_LOCK_BIAS);
/* FIXME: It is a value of bad manners for pthread.
But we shouldn't keep an ID of not-owner. */
lock->writer_thread = -1;
/* atomic operation may be safer about memory order. */
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
__sync_synchronize();
}
#else
lock->writer_count--;
if (lock->writer_count == 0) {
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
}
#endif
#ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
#endif
/* If there may be waiters, signal the lock */
if (UNIV_UNLIKELY(lock->waiters)
&& lock->writer_count == 0) {
sg = TRUE;
rw_lock_set_waiters(lock, 0);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if (last) {
#else
if (lock->writer_count == 0) {
#endif
if(lock->s_waiters){
s_sg = TRUE;
rw_lock_set_s_waiters(lock, 0);
}
if(lock->x_waiters){
x_sg = TRUE;
rw_lock_set_x_waiters(lock, 0);
}
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(&(lock->mutex));
#endif
if (UNIV_UNLIKELY(sg)) {
if (UNIV_UNLIKELY(s_sg)) {
os_event_set(lock->s_event);
sync_array_object_signalled(sync_primary_wait_array);
}
if (UNIV_UNLIKELY(x_sg)) {
#ifdef __WIN__
/* I doubt the necessity of it. */
os_event_set(lock->wait_ex_event);
#endif
os_event_set(lock->event);
os_event_set(lock->x_event);
sync_array_object_signalled(sync_primary_wait_array);
}
......@@ -493,9 +710,13 @@ rw_lock_x_unlock_direct(
ut_ad(lock->writer_count > 0);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if(__sync_sub_and_fetch(&(lock->writer_count),1) == 0) {
#else
lock->writer_count--;
if (lock->writer_count == 0) {
#endif
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
}
......@@ -503,7 +724,9 @@ rw_lock_x_unlock_direct(
rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
#endif
ut_ad(!lock->waiters);
ut_ad(!lock->s_waiters);
ut_ad(!lock->x_waiters);
ut_ad(!lock->wait_ex_waiters);
ut_ad(rw_lock_validate(lock));
#ifdef UNIV_SYNC_PERF_STAT
......
......@@ -60,6 +60,17 @@ thr_local_get_in_ibuf_field(void);
/*=============================*/
/* out: pointer to the in_ibuf field */
/*************************************************************************
Return local hash table informations. */
ulint
thr_local_hash_cells(void);
/*=======================*/
ulint
thr_local_hash_nodes(void);
/*=======================*/
#ifndef UNIV_NONINL
#include "thr0loc.ic"
#endif
......
......@@ -12,6 +12,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 1
#define INNODB_VERSION_MINOR 0
#define INNODB_VERSION_BUGFIX 2
#define PERCONA_INNODB_VERSION -1
/* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins;
......@@ -23,13 +24,14 @@ component, i.e. we show M.N.P as M.N */
(INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR)
/* auxiliary macros to help creating the version as string */
#define __INNODB_VERSION(a, b, c) (#a "." #b "." #c)
#define _INNODB_VERSION(a, b, c) __INNODB_VERSION(a, b, c)
#define __INNODB_VERSION(a, b, c, d) (#a "." #b "." #c "." #d)
#define _INNODB_VERSION(a, b, c, d) __INNODB_VERSION(a, b, c, d)
#define INNODB_VERSION_STR \
_INNODB_VERSION(INNODB_VERSION_MAJOR, \
INNODB_VERSION_MINOR, \
INNODB_VERSION_BUGFIX)
INNODB_VERSION_BUGFIX, \
PERCONA_INNODB_VERSION)
#ifdef MYSQL_DYNAMIC_PLUGIN
/* In the dynamic plugin, redefine some externally visible symbols
......
......@@ -4294,8 +4294,8 @@ lock_rec_print(
putc('\n', file);
if ( srv_show_verbose_locks ) {
block = buf_page_try_get(space, page_no, &mtr);
if (block) {
for (i = 0; i < lock_rec_get_n_bits(lock); i++) {
......@@ -4319,7 +4319,7 @@ lock_rec_print(
fprintf(file, "Record lock, heap no %lu\n", (ulong) i);
}
}
}
mtr_commit(&mtr);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
......@@ -4498,7 +4498,7 @@ lock_print_info_all_transactions(
}
}
if (!srv_print_innodb_lock_monitor) {
if (!srv_print_innodb_lock_monitor && !srv_show_locks_held) {
nth_trx++;
goto loop;
}
......@@ -4557,8 +4557,8 @@ lock_print_info_all_transactions(
nth_lock++;
if (nth_lock >= 10) {
fputs("10 LOCKS PRINTED FOR THIS TRX:"
if (nth_lock >= srv_show_locks_held) {
fputs("TOO LOCKS PRINTED FOR THIS TRX:"
" SUPPRESSING FURTHER PRINTS\n",
file);
......
......@@ -3263,9 +3263,9 @@ log_print(
"Modified age %lu\n"
"Checkpoint age %lu\n",
(ulong) log_sys->max_checkpoint_age,
(ulong) ut_dulint_minus(log_sys->lsn,
(ulong) (log_sys->lsn -
log_buf_pool_get_oldest_modification()),
(ulong) ut_dulint_minus(log_sys->lsn, log_sys->last_checkpoint_lsn));
(ulong) (log_sys->lsn - log_sys->last_checkpoint_lsn));
current_time = time(NULL);
......
......@@ -132,6 +132,10 @@ UNIV_INTERN ulint srv_log_file_size = ULINT_MAX;
UNIV_INTERN ulint srv_log_buffer_size = ULINT_MAX;
UNIV_INTERN ulong srv_flush_log_at_trx_commit = 1;
UNIV_INTERN ulint srv_show_locks_held = 10;
UNIV_INTERN ulint srv_show_verbose_locks = 0;
/* The sort order table of the MySQL latin1_swedish_ci character set
collation */
UNIV_INTERN const byte* srv_latin1_ordering;
......@@ -1625,6 +1629,14 @@ srv_printf_innodb_monitor(
time_t current_time;
ulint n_reserved;
ulint btr_search_sys_subtotal;
ulint lock_sys_subtotal;
ulint recv_sys_subtotal;
ulint io_counter_subtotal;
ulint i;
trx_t* trx;
mutex_enter(&srv_innodb_monitor_mutex);
current_time = time(NULL);
......@@ -1668,24 +1680,6 @@ srv_printf_innodb_monitor(
mutex_exit(&dict_foreign_err_mutex);
lock_print_info_summary(file);
if (trx_start) {
long t = ftell(file);
if (t < 0) {
*trx_start = ULINT_UNDEFINED;
} else {
*trx_start = (ulint) t;
}
}
lock_print_info_all_transactions(file);
if (trx_end) {
long t = ftell(file);
if (t < 0) {
*trx_end = ULINT_UNDEFINED;
} else {
*trx_end = (ulint) t;
}
}
fputs("--------\n"
"FILE I/O\n"
"--------\n", file);
......@@ -1720,6 +1714,80 @@ srv_printf_innodb_monitor(
"; in additional pool allocated " ULINTPF "\n",
ut_total_allocated_memory,
mem_pool_get_reserved(mem_comm_pool));
/* Calcurate reserved memories */
if (btr_search_sys && btr_search_sys->hash_index->heap) {
btr_search_sys_subtotal = mem_heap_get_size(btr_search_sys->hash_index->heap);
} else {
btr_search_sys_subtotal = 0;
for (i=0; i < btr_search_sys->hash_index->n_mutexes; i++) {
btr_search_sys_subtotal += mem_heap_get_size(btr_search_sys->hash_index->heaps[i]);
}
}
lock_sys_subtotal = 0;
if (trx_sys) {
mutex_enter(&kernel_mutex);
trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
while (trx) {
lock_sys_subtotal += ((trx->lock_heap) ? mem_heap_get_size(trx->lock_heap) : 0);
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx);
}
mutex_exit(&kernel_mutex);
}
recv_sys_subtotal = ((recv_sys && recv_sys->addr_hash)
? mem_heap_get_size(recv_sys->heap) : 0);
fprintf(file,
"Internal hash tables (constant factor + variable factor)\n"
" Adaptive hash index %lu \t(%lu + %lu)\n"
" Page hash %lu\n"
" Dictionary cache %lu \t(%lu + %lu)\n"
" File system %lu \t(%lu + %lu)\n"
" Lock system %lu \t(%lu + %lu)\n"
" Recovery system %lu \t(%lu + %lu)\n"
" Threads %lu \t(%lu + %lu)\n",
(ulong) (btr_search_sys
? (btr_search_sys->hash_index->n_cells * sizeof(hash_cell_t)) : 0)
+ btr_search_sys_subtotal,
(ulong) (btr_search_sys
? (btr_search_sys->hash_index->n_cells * sizeof(hash_cell_t)) : 0),
(ulong) btr_search_sys_subtotal,
(ulong) (buf_pool->page_hash->n_cells * sizeof(hash_cell_t)),
(ulong) (dict_sys ? ((dict_sys->table_hash->n_cells
+ dict_sys->table_id_hash->n_cells
) * sizeof(hash_cell_t)
+ dict_sys->size) : 0),
(ulong) (dict_sys ? ((dict_sys->table_hash->n_cells
+ dict_sys->table_id_hash->n_cells
) * sizeof(hash_cell_t)) : 0),
(ulong) (dict_sys ? (dict_sys->size) : 0),
(ulong) (fil_system_hash_cells() * sizeof(hash_cell_t)
+ fil_system_hash_nodes()),
(ulong) (fil_system_hash_cells() * sizeof(hash_cell_t)),
(ulong) fil_system_hash_nodes(),
(ulong) ((lock_sys ? (lock_sys->rec_hash->n_cells * sizeof(hash_cell_t)) : 0)
+ lock_sys_subtotal),
(ulong) (lock_sys ? (lock_sys->rec_hash->n_cells * sizeof(hash_cell_t)) : 0),
(ulong) lock_sys_subtotal,
(ulong) (((recv_sys && recv_sys->addr_hash)
? (recv_sys->addr_hash->n_cells * sizeof(hash_cell_t)) : 0)
+ recv_sys_subtotal),
(ulong) ((recv_sys && recv_sys->addr_hash)
? (recv_sys->addr_hash->n_cells * sizeof(hash_cell_t)) : 0),
(ulong) recv_sys_subtotal,
(ulong) (thr_local_hash_cells() * sizeof(hash_cell_t)
+ thr_local_hash_nodes()),
(ulong) (thr_local_hash_cells() * sizeof(hash_cell_t)),
(ulong) thr_local_hash_nodes());
fprintf(file, "Dictionary memory allocated " ULINTPF "\n",
dict_sys->size);
......@@ -1778,6 +1846,25 @@ srv_printf_innodb_monitor(
srv_n_rows_deleted_old = srv_n_rows_deleted;
srv_n_rows_read_old = srv_n_rows_read;
lock_print_info_summary(file);
if (trx_start) {
long t = ftell(file);
if (t < 0) {
*trx_start = ULINT_UNDEFINED;
} else {
*trx_start = (ulint) t;
}
}
lock_print_info_all_transactions(file);
if (trx_end) {
long t = ftell(file);
if (t < 0) {
*trx_end = ULINT_UNDEFINED;
} else {
*trx_end = (ulint) t;
}
}
fputs("----------------------------\n"
"END OF INNODB MONITOR OUTPUT\n"
"============================\n", file);
......@@ -2214,7 +2301,7 @@ srv_master_thread(
ibool skip_sleep = FALSE;
ulint i;
dulint oldest_lsn;
ib_uint64_t oldest_lsn;
#ifdef UNIV_DEBUG_THREAD_CREATION
fprintf(stderr, "Master thread starts, id %lu\n",
......@@ -2336,12 +2423,12 @@ srv_master_thread(
mutex_enter(&(log_sys->mutex));
oldest_lsn = buf_pool_get_oldest_modification();
if (ut_dulint_is_zero(oldest_lsn)) {
if (oldest_lsn == 0) {
mutex_exit(&(log_sys->mutex));
} else {
if (ut_dulint_minus(log_sys->lsn, oldest_lsn)
if ((log_sys->lsn - oldest_lsn)
> (log_sys->max_checkpoint_age) - ((log_sys->max_checkpoint_age) / 4)) {
/* 2nd defence line (max_checkpoint_age * 3/4) */
......@@ -2349,9 +2436,9 @@ srv_master_thread(
mutex_exit(&(log_sys->mutex));
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(100),
ut_dulint_max);
IB_ULONGLONG_MAX);
skip_sleep = TRUE;
} else if (ut_dulint_minus(log_sys->lsn, oldest_lsn)
} else if ((log_sys->lsn - oldest_lsn)
> (log_sys->max_checkpoint_age)/2 ) {
/* 1st defence line (max_checkpoint_age * 1/2) */
......@@ -2359,7 +2446,7 @@ srv_master_thread(
mutex_exit(&(log_sys->mutex));
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(10),
ut_dulint_max);
IB_ULONGLONG_MAX);
skip_sleep = TRUE;
} else {
mutex_exit(&(log_sys->mutex));
......
......@@ -307,13 +307,13 @@ sync_cell_event_reset(
{
if (type == SYNC_MUTEX) {
return(os_event_reset(((mutex_t *) object)->event));
#ifdef __WIN__
} else if (type == RW_LOCK_WAIT_EX) {
return(os_event_reset(
((rw_lock_t *) object)->wait_ex_event));
#endif
} else {
return(os_event_reset(((rw_lock_t *) object)->event));
} else if (type == RW_LOCK_SHARED) {
return(os_event_reset(((rw_lock_t *) object)->s_event));
} else { /* RW_LOCK_EX */
return(os_event_reset(((rw_lock_t *) object)->x_event));
}
}
......@@ -413,15 +413,12 @@ sync_array_wait_event(
if (cell->request_type == SYNC_MUTEX) {
event = ((mutex_t*) cell->wait_object)->event;
#ifdef __WIN__
/* On windows if the thread about to wait is the one which
has set the state of the rw_lock to RW_LOCK_WAIT_EX, then
it waits on a special event i.e.: wait_ex_event. */
} else if (cell->request_type == RW_LOCK_WAIT_EX) {
event = ((rw_lock_t*) cell->wait_object)->wait_ex_event;
#endif
} else if (cell->request_type == RW_LOCK_SHARED) {
event = ((rw_lock_t*) cell->wait_object)->s_event;
} else {
event = ((rw_lock_t*) cell->wait_object)->event;
event = ((rw_lock_t*) cell->wait_object)->x_event;
}
cell->waiting = TRUE;
......@@ -462,6 +459,7 @@ sync_array_cell_print(
mutex_t* mutex;
rw_lock_t* rwlock;
ulint type;
ulint writer;
type = cell->request_type;
......@@ -491,12 +489,10 @@ sync_array_cell_print(
(ulong) mutex->waiters);
} else if (type == RW_LOCK_EX
#ifdef __WIN__
|| type == RW_LOCK_WAIT_EX
#endif
|| type == RW_LOCK_SHARED) {
fputs(type == RW_LOCK_EX ? "X-lock on" : "S-lock on", file);
fputs(type == RW_LOCK_SHARED ? "S-lock on" : "X-lock on", file);
rwlock = cell->old_wait_rw_lock;
......@@ -504,22 +500,24 @@ sync_array_cell_print(
" RW-latch at %p created in file %s line %lu\n",
(void*) rwlock, rwlock->cfile_name,
(ulong) rwlock->cline);
if (rwlock->writer != RW_LOCK_NOT_LOCKED) {
writer = rw_lock_get_writer(rwlock);
if (writer != RW_LOCK_NOT_LOCKED) {
fprintf(file,
"a writer (thread id %lu) has"
" reserved it in mode %s",
(ulong) os_thread_pf(rwlock->writer_thread),
rwlock->writer == RW_LOCK_EX
writer == RW_LOCK_EX
? " exclusive\n"
: " wait exclusive\n");
}
fprintf(file,
"number of readers %lu, waiters flag %lu\n"
"number of readers %lu, s_waiters flag %lu, x_waiters flag %lu\n"
"Last time read locked in file %s line %lu\n"
"Last time write locked in file %s line %lu\n",
(ulong) rwlock->reader_count,
(ulong) rwlock->waiters,
(ulong) rwlock->s_waiters,
(ulong) (rwlock->x_waiters || rwlock->wait_ex_waiters),
rwlock->last_s_file_name,
(ulong) rwlock->last_s_line,
rwlock->last_x_file_name,
......@@ -844,11 +842,15 @@ sync_array_object_signalled(
/*========================*/
sync_array_t* arr) /* in: wait array */
{
#ifdef HAVE_GCC_ATOMIC_BUILTINS
__sync_fetch_and_add(&(arr->sg_count),1);
#else
sync_array_enter(arr);
arr->sg_count++;
sync_array_exit(arr);
#endif
}
/**************************************************************************
......@@ -889,19 +891,23 @@ sync_arr_wake_threads_if_sema_free(void)
mutex = cell->wait_object;
os_event_set(mutex->event);
#ifdef __WIN__
} else if (cell->request_type
== RW_LOCK_WAIT_EX) {
rw_lock_t* lock;
lock = cell->wait_object;
os_event_set(lock->wait_ex_event);
#endif
} else if (cell->request_type
== RW_LOCK_SHARED) {
rw_lock_t* lock;
lock = cell->wait_object;
os_event_set(lock->s_event);
} else {
rw_lock_t* lock;
lock = cell->wait_object;
os_event_set(lock->event);
os_event_set(lock->x_event);
}
}
}
......
......@@ -119,6 +119,7 @@ rw_lock_create_func(
/* If this is the very first time a synchronization object is
created, then the following call initializes the sync system. */
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
lock->mutex.cfile_name = cfile_name;
......@@ -128,8 +129,14 @@ rw_lock_create_func(
lock->mutex.cmutex_name = cmutex_name;
lock->mutex.mutex_type = 1;
#endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
#endif /* !HAVE_GCC_ATOMIC_BUILTINS */
rw_lock_set_waiters(lock, 0);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
lock->lock_word = RW_LOCK_BIAS;
#endif
rw_lock_set_s_waiters(lock, 0);
rw_lock_set_x_waiters(lock, 0);
rw_lock_set_wx_waiters(lock, 0);
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
lock->writer_count = 0;
rw_lock_set_reader_count(lock, 0);
......@@ -151,11 +158,9 @@ rw_lock_create_func(
lock->last_x_file_name = "not yet reserved";
lock->last_s_line = 0;
lock->last_x_line = 0;
lock->event = os_event_create(NULL);
#ifdef __WIN__
lock->s_event = os_event_create(NULL);
lock->x_event = os_event_create(NULL);
lock->wait_ex_event = os_event_create(NULL);
#endif
mutex_enter(&rw_lock_list_mutex);
......@@ -181,19 +186,21 @@ rw_lock_free(
{
ut_ad(rw_lock_validate(lock));
ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
ut_a(rw_lock_get_waiters(lock) == 0);
ut_a(rw_lock_get_s_waiters(lock) == 0);
ut_a(rw_lock_get_x_waiters(lock) == 0);
ut_a(rw_lock_get_wx_waiters(lock) == 0);
ut_a(rw_lock_get_reader_count(lock) == 0);
lock->magic_n = 0;
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_free(rw_lock_get_mutex(lock));
#endif
mutex_enter(&rw_lock_list_mutex);
os_event_free(lock->event);
#ifdef __WIN__
os_event_free(lock->s_event);
os_event_free(lock->x_event);
os_event_free(lock->wait_ex_event);
#endif
if (UT_LIST_GET_PREV(list, lock)) {
ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
......@@ -211,6 +218,8 @@ rw_lock_free(
/**********************************************************************
Checks that the rw-lock has been initialized and that there are no
simultaneous shared and exclusive locks. */
/* MEMO: If HAVE_GCC_ATOMIC_BUILTINS, we should use this function statically. */
UNIV_INTERN
ibool
rw_lock_validate(
......@@ -219,7 +228,9 @@ rw_lock_validate(
{
ut_a(lock);
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_enter(rw_lock_get_mutex(lock));
#endif
ut_a(lock->magic_n == RW_LOCK_MAGIC_N);
ut_a((rw_lock_get_reader_count(lock) == 0)
......@@ -227,11 +238,17 @@ rw_lock_validate(
ut_a((rw_lock_get_writer(lock) == RW_LOCK_EX)
|| (rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX)
|| (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED));
ut_a((rw_lock_get_waiters(lock) == 0)
|| (rw_lock_get_waiters(lock) == 1));
ut_a((rw_lock_get_s_waiters(lock) == 0)
|| (rw_lock_get_s_waiters(lock) == 1));
ut_a((rw_lock_get_x_waiters(lock) == 0)
|| (rw_lock_get_x_waiters(lock) == 1));
ut_a((rw_lock_get_wx_waiters(lock) == 0)
|| (rw_lock_get_wx_waiters(lock) == 1));
ut_a((lock->writer != RW_LOCK_EX) || (lock->writer_count > 0));
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(rw_lock_get_mutex(lock));
#endif
return(TRUE);
}
......@@ -258,13 +275,14 @@ rw_lock_s_lock_spin(
ut_ad(rw_lock_validate(lock));
lock_loop:
i = 0;
spin_loop:
rw_s_spin_wait_count++;
/* Spin waiting for the writer field to become free */
i = 0;
while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
&& i < SYNC_SPIN_ROUNDS) {
while (i < SYNC_SPIN_ROUNDS
&& rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
}
......@@ -285,15 +303,27 @@ rw_lock_s_lock_spin(
lock->cfile_name, (ulong) lock->cline, (ulong) i);
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_enter(rw_lock_get_mutex(lock));
#endif
/* We try once again to obtain the lock */
if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(rw_lock_get_mutex(lock));
#endif
return; /* Success */
} else {
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/* like sync0sync.c doing */
i++;
if (i < SYNC_SPIN_ROUNDS) {
goto spin_loop;
}
#endif
/* If we get here, locking did not succeed, we may
suspend the thread to wait in the wait array */
......@@ -304,9 +334,19 @@ rw_lock_s_lock_spin(
file_name, line,
&index);
rw_lock_set_waiters(lock, 1);
rw_lock_set_s_waiters(lock, 1);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/* like sync0sync.c doing */
for (i = 0; i < 4; i++) {
if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
sync_array_free_cell(sync_primary_wait_array, index);
return; /* Success */
}
}
#else
mutex_exit(rw_lock_get_mutex(lock));
#endif
if (srv_print_latch_waits) {
fprintf(stderr,
......@@ -343,13 +383,19 @@ rw_lock_x_lock_move_ownership(
{
ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_enter(&(lock->mutex));
#endif
lock->writer_thread = os_thread_get_curr_id();
lock->pass = 0;
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(&(lock->mutex));
#else
__sync_synchronize();
#endif
}
/**********************************************************************
......@@ -367,6 +413,89 @@ rw_lock_x_lock_low(
const char* file_name,/* in: file name where lock requested */
ulint line) /* in: line where requested */
{
#ifdef HAVE_GCC_ATOMIC_BUILTINS
os_thread_id_t curr_thread = os_thread_get_curr_id();
/* try to lock writer */
if(__sync_lock_test_and_set(&(lock->writer),RW_LOCK_EX)
== RW_LOCK_NOT_LOCKED) {
/* success */
/* obtain RW_LOCK_WAIT_EX right */
lock->writer_thread = curr_thread;
lock->pass = pass;
lock->writer_is_wait_ex = TRUE;
/* atomic operation may be safer about memory order. */
__sync_synchronize();
#ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
file_name, line);
#endif
}
if (!os_thread_eq(lock->writer_thread, curr_thread)) {
return(RW_LOCK_NOT_LOCKED);
}
switch(rw_lock_get_writer(lock)) {
case RW_LOCK_WAIT_EX:
/* have right to try x-lock */
if (lock->lock_word == RW_LOCK_BIAS) {
/* try x-lock */
if(__sync_sub_and_fetch(&(lock->lock_word),
RW_LOCK_BIAS) == 0) {
/* success */
lock->pass = pass;
lock->writer_is_wait_ex = FALSE;
__sync_fetch_and_add(&(lock->writer_count),1);
#ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX);
rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
file_name, line);
#endif
lock->last_x_file_name = file_name;
lock->last_x_line = line;
/* Locking succeeded, we may return */
return(RW_LOCK_EX);
} else {
/* fail */
__sync_fetch_and_add(&(lock->lock_word),
RW_LOCK_BIAS);
}
}
/* There are readers, we have to wait */
return(RW_LOCK_WAIT_EX);
break;
case RW_LOCK_EX:
/* already have x-lock */
if ((lock->pass == 0)&&(pass == 0)) {
__sync_fetch_and_add(&(lock->writer_count),1);
#ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name,
line);
#endif
lock->last_x_file_name = file_name;
lock->last_x_line = line;
/* Locking succeeded, we may return */
return(RW_LOCK_EX);
}
return(RW_LOCK_NOT_LOCKED);
break;
default: /* ??? */
return(RW_LOCK_NOT_LOCKED);
}
#else /* HAVE_GCC_ATOMIC_BUILTINS */
ut_ad(mutex_own(rw_lock_get_mutex(lock)));
if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) {
......@@ -447,6 +576,7 @@ rw_lock_x_lock_low(
/* Locking succeeded, we may return */
return(RW_LOCK_EX);
}
#endif /* HAVE_GCC_ATOMIC_BUILTINS */
/* Locking did not succeed */
return(RW_LOCK_NOT_LOCKED);
......@@ -472,19 +602,33 @@ rw_lock_x_lock_func(
ulint line) /* in: line where requested */
{
ulint index; /* index of the reserved wait cell */
ulint state; /* lock state acquired */
ulint state = RW_LOCK_NOT_LOCKED; /* lock state acquired */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
ulint prev_state = RW_LOCK_NOT_LOCKED;
#endif
ulint i; /* spin round count */
ut_ad(rw_lock_validate(lock));
lock_loop:
i = 0;
#ifdef HAVE_GCC_ATOMIC_BUILTINS
prev_state = state;
#else
/* Acquire the mutex protecting the rw-lock fields */
mutex_enter_fast(&(lock->mutex));
#endif
state = rw_lock_x_lock_low(lock, pass, file_name, line);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if (state != prev_state) i=0; /* if progress, reset counter. */
#else
mutex_exit(&(lock->mutex));
#endif
spin_loop:
if (state == RW_LOCK_EX) {
return; /* Locking succeeded */
......@@ -492,10 +636,9 @@ rw_lock_x_lock_func(
} else if (state == RW_LOCK_NOT_LOCKED) {
/* Spin waiting for the writer field to become free */
i = 0;
while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
&& i < SYNC_SPIN_ROUNDS) {
while (i < SYNC_SPIN_ROUNDS
&& rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0,
srv_spin_wait_delay));
......@@ -509,9 +652,12 @@ rw_lock_x_lock_func(
} else if (state == RW_LOCK_WAIT_EX) {
/* Spin waiting for the reader count field to become zero */
i = 0;
#ifdef HAVE_GCC_ATOMIC_BUILTINS
while (lock->lock_word != RW_LOCK_BIAS
#else
while (rw_lock_get_reader_count(lock) != 0
#endif
&& i < SYNC_SPIN_ROUNDS) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0,
......@@ -524,7 +670,6 @@ rw_lock_x_lock_func(
os_thread_yield();
}
} else {
i = 0; /* Eliminate a compiler warning */
ut_error;
}
......@@ -541,34 +686,69 @@ rw_lock_x_lock_func(
/* We try once again to obtain the lock. Acquire the mutex protecting
the rw-lock fields */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
prev_state = state;
#else
mutex_enter(rw_lock_get_mutex(lock));
#endif
state = rw_lock_x_lock_low(lock, pass, file_name, line);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
if (state != prev_state) i=0; /* if progress, reset counter. */
#endif
if (state == RW_LOCK_EX) {
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(rw_lock_get_mutex(lock));
#endif
return; /* Locking succeeded */
}
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/* like sync0sync.c doing */
i++;
if (i < SYNC_SPIN_ROUNDS) {
goto spin_loop;
}
#endif
rw_x_system_call_count++;
sync_array_reserve_cell(sync_primary_wait_array,
lock,
#ifdef __WIN__
/* On windows RW_LOCK_WAIT_EX signifies
that this thread should wait on the
special wait_ex_event. */
(state == RW_LOCK_WAIT_EX)
? RW_LOCK_WAIT_EX :
#endif
RW_LOCK_EX,
file_name, line,
&index);
rw_lock_set_waiters(lock, 1);
if (state == RW_LOCK_WAIT_EX) {
rw_lock_set_wx_waiters(lock, 1);
} else {
rw_lock_set_x_waiters(lock, 1);
}
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/* like sync0sync.c doing */
for (i = 0; i < 4; i++) {
prev_state = state;
state = rw_lock_x_lock_low(lock, pass, file_name, line);
if (state == RW_LOCK_EX) {
sync_array_free_cell(sync_primary_wait_array, index);
return; /* Locking succeeded */
}
if (state != prev_state) {
/* retry! */
sync_array_free_cell(sync_primary_wait_array, index);
goto lock_loop;
}
}
#else
mutex_exit(rw_lock_get_mutex(lock));
#endif
if (srv_print_latch_waits) {
fprintf(stderr,
......@@ -730,7 +910,9 @@ rw_lock_own(
ut_ad(lock);
ut_ad(rw_lock_validate(lock));
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_enter(&(lock->mutex));
#endif
info = UT_LIST_GET_FIRST(lock->debug_list);
......@@ -740,7 +922,9 @@ rw_lock_own(
&& (info->pass == 0)
&& (info->lock_type == lock_type)) {
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(&(lock->mutex));
#endif
/* Found! */
return(TRUE);
......@@ -748,7 +932,9 @@ rw_lock_own(
info = UT_LIST_GET_NEXT(list, info);
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(&(lock->mutex));
#endif
return(FALSE);
}
......@@ -770,21 +956,25 @@ rw_lock_is_locked(
ut_ad(lock);
ut_ad(rw_lock_validate(lock));
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_enter(&(lock->mutex));
#endif
if (lock_type == RW_LOCK_SHARED) {
if (lock->reader_count > 0) {
ret = TRUE;
}
} else if (lock_type == RW_LOCK_EX) {
if (lock->writer == RW_LOCK_EX) {
if (rw_lock_get_writer(lock) == RW_LOCK_EX) {
ret = TRUE;
}
} else {
ut_error;
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(&(lock->mutex));
#endif
return(ret);
}
......@@ -814,16 +1004,26 @@ rw_lock_list_print_info(
count++;
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_enter(&(lock->mutex));
#endif
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
|| (rw_lock_get_reader_count(lock) != 0)
|| (rw_lock_get_waiters(lock) != 0)) {
|| (rw_lock_get_s_waiters(lock) != 0)
|| (rw_lock_get_x_waiters(lock) != 0)
|| (rw_lock_get_wx_waiters(lock) != 0)) {
fprintf(file, "RW-LOCK: %p ", (void*) lock);
if (rw_lock_get_waiters(lock)) {
fputs(" Waiters for the lock exist\n", file);
if (rw_lock_get_s_waiters(lock)) {
fputs(" s_waiters for the lock exist,", file);
}
if (rw_lock_get_x_waiters(lock)) {
fputs(" x_waiters for the lock exist\n", file);
}
if (rw_lock_get_wx_waiters(lock)) {
fputs(" wait_ex_waiters for the lock exist\n", file);
} else {
putc('\n', file);
}
......@@ -835,7 +1035,9 @@ rw_lock_list_print_info(
}
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(&(lock->mutex));
#endif
lock = UT_LIST_GET_NEXT(list, lock);
}
......@@ -860,10 +1062,18 @@ rw_lock_print(
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
|| (rw_lock_get_reader_count(lock) != 0)
|| (rw_lock_get_waiters(lock) != 0)) {
|| (rw_lock_get_s_waiters(lock) != 0)
|| (rw_lock_get_x_waiters(lock) != 0)
|| (rw_lock_get_wx_waiters(lock) != 0)) {
if (rw_lock_get_waiters(lock)) {
fputs(" Waiters for the lock exist\n", stderr);
if (rw_lock_get_s_waiters(lock)) {
fputs(" s_waiters for the lock exist,", stderr);
}
if (rw_lock_get_x_waiters(lock)) {
fputs(" x_waiters for the lock exist\n", stderr);
}
if (rw_lock_get_wx_waiters(lock)) {
fputs(" wait_ex_waiters for the lock exist\n", stderr);
} else {
putc('\n', stderr);
}
......@@ -922,14 +1132,18 @@ rw_lock_n_locked(void)
lock = UT_LIST_GET_FIRST(rw_lock_list);
while (lock != NULL) {
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_enter(rw_lock_get_mutex(lock));
#endif
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
|| (rw_lock_get_reader_count(lock) != 0)) {
count++;
}
#ifndef HAVE_GCC_ATOMIC_BUILTINS
mutex_exit(rw_lock_get_mutex(lock));
#endif
lock = UT_LIST_GET_NEXT(list, lock);
}
......
......@@ -32,6 +32,7 @@ static mutex_t thr_local_mutex;
/* The hash table. The module is not yet initialized when it is NULL. */
static hash_table_t* thr_local_hash = NULL;
ulint thr_local_hash_n_nodes = 0;
/* The private data for each thread should be put to
the structure below and the accessor functions written
......@@ -177,6 +178,7 @@ thr_local_create(void)
os_thread_pf(os_thread_get_curr_id()),
local);
thr_local_hash_n_nodes++;
mutex_exit(&thr_local_mutex);
}
......@@ -204,6 +206,7 @@ thr_local_free(
HASH_DELETE(thr_local_t, hash, thr_local_hash,
os_thread_pf(id), local);
thr_local_hash_n_nodes--;
mutex_exit(&thr_local_mutex);
......@@ -226,3 +229,29 @@ thr_local_init(void)
mutex_create(&thr_local_mutex, SYNC_THR_LOCAL);
}
/*************************************************************************
Return local hash table informations. */
ulint
thr_local_hash_cells(void)
/*======================*/
{
if (thr_local_hash) {
return (thr_local_hash->n_cells);
} else {
return 0;
}
}
ulint
thr_local_hash_nodes(void)
/*======================*/
{
if (thr_local_hash) {
return (thr_local_hash_n_nodes
* (sizeof(thr_local_t) + MEM_BLOCK_HEADER_SIZE));
} else {
return 0;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment