Commit 6e8805e0 authored by marko's avatar marko

branches/innodb+: Merge revisions 4072:4150 from branches/zip:

  ------------------------------------------------------------------------
  r4074 | vasil | 2009-01-31 08:05:24 +0200 (Sat, 31 Jan 2009) | 4 lines

  branches/zip:

  Adjust the failing patch patches/information_schema.diff.
  ------------------------------------------------------------------------
  r4076 | vasil | 2009-02-02 09:32:04 +0200 (Mon, 02 Feb 2009) | 4 lines

  branches/zip:

  Add ChangeLog entry for the change in r4072.
  ------------------------------------------------------------------------
  r4077 | marko | 2009-02-02 10:48:05 +0200 (Mon, 02 Feb 2009) | 2 lines

  branches/zip: innobase_start_or_create_for_mysql(): Remove a factual error
  in the function comment.  Parameters are not read from a file "srv_init".
  ------------------------------------------------------------------------
  r4081 | marko | 2009-02-02 14:28:17 +0200 (Mon, 02 Feb 2009) | 4 lines

  branches/zip: Enclose some backup functions in #ifdef UNIV_HOTBACKUP.

  recv_read_cp_info_for_backup(), recv_scan_log_seg_for_backup():
  These functions are only called by InnoDB Hot Backup.
  ------------------------------------------------------------------------
  r4082 | vasil | 2009-02-02 18:24:08 +0200 (Mon, 02 Feb 2009) | 10 lines

  branches/zip:

  Fix a mysql-test failure in innodb-zip:

  main.innodb-zip                          [ fail ]
          Test ended at 2009-02-02 18:13:25

  CURRENT_TEST: main.innodb-zip
  mysqltest: At line 160: Found line beginning with --  that didn't contain a valid mysqltest command, check your syntax or use # if you intended to write a comment
  ------------------------------------------------------------------------
  r4083 | vasil | 2009-02-02 18:33:20 +0200 (Mon, 02 Feb 2009) | 6 lines

  branches/zip:

  Fix the failing innodb-zip test to restore the environment as it was before
  the test execution because a newly added feature in the mysql-test framework
  does check for this.
  ------------------------------------------------------------------------
  r4088 | calvin | 2009-02-03 02:35:56 +0200 (Tue, 03 Feb 2009) | 8 lines

  branches/zip: fix a compiler error and a warning

  Both are minor changes:
  1) Compiler error introduced in r4072: double ';' at the end.
  2) Warning introduced in r3613: \mem\mem0pool.c(481) :
  warning C4098: 'mem_area_free' : 'void' function returning a value

  Approved by: Sunny (IM)
  ------------------------------------------------------------------------
  r4098 | marko | 2009-02-03 09:52:45 +0200 (Tue, 03 Feb 2009) | 4 lines

  branches/zip: mem_area_free(): Correct a bug that was introduced in r4088.
  free() is not the same as ut_free().  ut_free() pairs with ut_malloc(),
  not malloc().  free() pairs with malloc() and some other functions.
  ------------------------------------------------------------------------
  r4114 | marko | 2009-02-04 16:09:24 +0200 (Wed, 04 Feb 2009) | 2 lines

  branches/zip: buf_block_align(): Fix a bogus debug assertion
  that was introduced in r4036, to address Issue #161.
  ------------------------------------------------------------------------
  r4139 | vasil | 2009-02-09 13:47:16 +0200 (Mon, 09 Feb 2009) | 5 lines

  branches/zip:

  Remove mysql-test/patches/bug35261.diff because that bug has been fixed
  in the MySQL repository.
  ------------------------------------------------------------------------
  r4141 | marko | 2009-02-09 15:35:50 +0200 (Mon, 09 Feb 2009) | 1 line

  branches/zip: fil_write_lsn_and_arch_no_to_file(): Plug a memory leak.
  ------------------------------------------------------------------------
  r4144 | inaam | 2009-02-10 01:36:25 +0200 (Tue, 10 Feb 2009) | 9 lines

  branches/zip            rb://30

  This patch changes the innodb mutexes and rw_locks implementation.
  On supported platforms it uses GCC builtin atomics. These changes
  are based on the patch sent by Mark Callaghan of Google under BSD
  license. More technical discussion can be found at rb://30

  Approved by: Heikki
  ------------------------------------------------------------------------
  r4145 | vasil | 2009-02-10 07:34:43 +0200 (Tue, 10 Feb 2009) | 9 lines

  branches/zip:

  Non-functional change: Fix a compilation warning introduced in r4144:

  gcc -DHAVE_CONFIG_H -I. -I../../include -I../../include -I../../include -I../../regex -I../../storage/innobase/include -I../../sql -I.   -Werror         -Wall -g   -MT libinnobase_a-sync0arr.o -MD -MP -MF .deps/libinnobase_a-sync0arr.Tpo -c -o libinnobase_a-sync0arr.o `test -f 'sync/sync0arr.c' || echo './'`sync/sync0arr.c
  cc1: warnings being treated as errors
  sync/sync0arr.c: In function 'sync_array_object_signalled':
  sync/sync0arr.c:869: warning: pointer targets in passing argument 1 of 'os_atomic_increment' differ in signedness
  ------------------------------------------------------------------------
  r4148 | marko | 2009-02-10 10:38:41 +0200 (Tue, 10 Feb 2009) | 12 lines

  branches/zip: Map ut_malloc(), ut_realloc(), ut_free() to
  malloc(), realloc(), free() when innodb_use_sys_malloc is set.

  ut_free_all_mem(): If innodb_use_sys_malloc is set, do nothing,
  because then ut_mem_block_list_inited will never be set.

  log_init(): Use mem_alloc() instead of ut_malloc(), so that the
  memory will be freed.  (Tested with Valgrind, although it is not
  clear why the memory would be freed.)

  rb://86 approved by Heikki Tuuri and Ken Jacobs.  This addresses Issue #168.
  ------------------------------------------------------------------------
  r4149 | marko | 2009-02-10 11:09:15 +0200 (Tue, 10 Feb 2009) | 1 line

  branches/zip: ChangeLog: Document recent changes.
  ------------------------------------------------------------------------
  r4150 | marko | 2009-02-10 11:51:43 +0200 (Tue, 10 Feb 2009) | 6 lines

  branches/zip: get_share(), free_share(): Make table locking case sensitive.
  If lower_case_table_names=1, MySQL will pass the table names in lower case.
  Thus, we can use a binary comparison (strcmp) in the hash table.

  rb://87 approved by Heikki Tuuri, to address Bug #41676 and Issue #167.
  ------------------------------------------------------------------------
parent fc59a0ad
2009-02-10 The InnoDB Team
* handler/ha_innodb.h, handler/ha_innodb.cc:
Fix Bug#41676 Table names are case insensitive in locking
2009-02-10 The InnoDB Team
* ut/ut0mem.c:
Map ut_malloc_low(), ut_realloc(), and ut_free() directly to
malloc(), realloc(), and free() when innodb_use_sys_malloc is set.
As a side effect, ut_total_allocated_memory ("Total memory allocated"
in the "BUFFER POOL AND MEMORY" section of SHOW ENGINE INNODB STATUS)
will exclude any memory allocated by these functions when
innodb_use_sys_malloc is set.
2009-02-10 The InnoDB Team
* btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, handler/ha_innodb.cc,
include/buf0buf.ic, include/os0sync.h, include/os0sync.ic,
include/srv0srv.h, include/sync0rw.h, include/sync0rw.ic,
include/sync0sync.h, include/sync0sync.ic, include/univ.i,
row/row0sel.c, srv/srv0srv.c, srv/srv0start.c,
sync/sync0arr.c, sync/sync0rw.c, sync/sync0sync.c:
On those platforms that support it, implement the synchronization
primitives of InnoDB mutexes and read/write locks with GCC atomic
builtins instead of Pthreads mutexes and InnoDB mutexes. These
changes are based on a patch supplied by Mark Callaghan of Google
under a BSD license.
2009-01-30 The InnoDB Team
* btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, handler/ha_innodb.cc,
include/btr0sea.h, include/buf0buf.h, include/sync0sync.h,
sync/sync0sync.c:
Make the configuration parameter innodb_adaptive_hash_index dynamic,
so that it can be changed at runtime.
2009-01-29 The InnoDB Team 2009-01-29 The InnoDB Team
* handler/ha_innodb.cc, include/ibuf0ibuf.h, include/ibuf0ibuf.ic, * handler/ha_innodb.cc, include/ibuf0ibuf.h, include/ibuf0ibuf.ic,
...@@ -107,7 +144,10 @@ ...@@ -107,7 +144,10 @@
mysql-test/innodb-use-sys-malloc.test: mysql-test/innodb-use-sys-malloc.test:
Implement the configuration parameter innodb_use_sys_malloc Implement the configuration parameter innodb_use_sys_malloc
(false by default), for disabling InnoDB's internal memory allocator (false by default), for disabling InnoDB's internal memory allocator
and using system malloc/free instead. and using system malloc/free instead. The "BUFFER POOL AND MEMORY"
section of SHOW ENGINE INNODB STATUS will report
"in additional pool allocated allocated 0" when
innodb_use_sys_malloc is set.
2008-12-30 The InnoDB Team 2008-12-30 The InnoDB Team
......
...@@ -16,6 +16,38 @@ by crashing the database and doing a roll-forward. ...@@ -16,6 +16,38 @@ by crashing the database and doing a roll-forward.
Created 10/16/1994 Heikki Tuuri Created 10/16/1994 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "btr0cur.h" #include "btr0cur.h"
...@@ -416,7 +448,7 @@ btr_cur_search_to_nth_level( ...@@ -416,7 +448,7 @@ btr_cur_search_to_nth_level(
/* Ibuf does not use adaptive hash; this is prevented by the /* Ibuf does not use adaptive hash; this is prevented by the
latch_mode check below. */ latch_mode check below. */
if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_NOT_LOCKED
&& latch_mode <= BTR_MODIFY_LEAF && latch_mode <= BTR_MODIFY_LEAF
&& info->last_hash_succ && info->last_hash_succ
&& !estimate && !estimate
......
...@@ -6,6 +6,39 @@ The index tree adaptive search ...@@ -6,6 +6,39 @@ The index tree adaptive search
Created 2/17/1996 Heikki Tuuri Created 2/17/1996 Heikki Tuuri
*************************************************************************/ *************************************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "btr0sea.h" #include "btr0sea.h"
#ifdef UNIV_NONINL #ifdef UNIV_NONINL
#include "btr0sea.ic" #include "btr0sea.ic"
...@@ -820,8 +853,8 @@ btr_search_guess_on_hash( ...@@ -820,8 +853,8 @@ btr_search_guess_on_hash(
} }
} }
ut_ad(btr_search_latch.writer != RW_LOCK_EX); ut_ad(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_EX);
ut_ad(btr_search_latch.reader_count > 0); ut_ad(rw_lock_get_reader_count(&btr_search_latch) > 0);
rec = ha_search_and_get_data(btr_search_sys->hash_index, fold); rec = ha_search_and_get_data(btr_search_sys->hash_index, fold);
......
...@@ -19,6 +19,38 @@ The database buffer buf_pool ...@@ -19,6 +19,38 @@ The database buffer buf_pool
Created 11/5/1995 Heikki Tuuri Created 11/5/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "buf0buf.h" #include "buf0buf.h"
...@@ -1016,7 +1048,7 @@ buf_pool_drop_hash_index(void) ...@@ -1016,7 +1048,7 @@ buf_pool_drop_hash_index(void)
ut_ad(!btr_search_enabled); ut_ad(!btr_search_enabled);
do { do {
buf_chunk_t* chunks = buf_pool->chunks;; buf_chunk_t* chunks = buf_pool->chunks;
buf_chunk_t* chunk = chunks + buf_pool->n_chunks; buf_chunk_t* chunk = chunks + buf_pool->n_chunks;
released_search_latch = FALSE; released_search_latch = FALSE;
...@@ -1924,12 +1956,52 @@ buf_block_align( ...@@ -1924,12 +1956,52 @@ buf_block_align(
buf_block_init() so that block[n].frame == buf_block_init() so that block[n].frame ==
block->frame + n * UNIV_PAGE_SIZE. Check it. */ block->frame + n * UNIV_PAGE_SIZE. Check it. */
ut_ad(block->frame == page_align(ptr)); ut_ad(block->frame == page_align(ptr));
/* The space id and page number should be #ifdef UNIV_DEBUG
stamped on the page. */ /* A thread that updates these fields must
ut_ad(block->page.space hold buf_pool_mutex and block->mutex. Acquire
== page_get_space_id(page_align(ptr))); only the latter. */
ut_ad(block->page.offset mutex_enter(&block->mutex);
== page_get_page_no(page_align(ptr)));
switch (buf_block_get_state(block)) {
case BUF_BLOCK_ZIP_FREE:
case BUF_BLOCK_ZIP_PAGE:
case BUF_BLOCK_ZIP_DIRTY:
/* These types should only be used in
the compressed buffer pool, whose
memory is allocated from
buf_pool->chunks, in UNIV_PAGE_SIZE
blocks flagged as BUF_BLOCK_MEMORY. */
ut_error;
break;
case BUF_BLOCK_NOT_USED:
case BUF_BLOCK_READY_FOR_USE:
case BUF_BLOCK_MEMORY:
/* Some data structures contain
"guess" pointers to file pages. The
file pages may have been freed and
reused. Do not complain. */
break;
case BUF_BLOCK_REMOVE_HASH:
/* buf_LRU_block_remove_hashed_page()
will overwrite the FIL_PAGE_OFFSET and
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID with
0xff and set the state to
BUF_BLOCK_REMOVE_HASH. */
ut_ad(page_get_space_id(page_align(ptr))
== 0xffffffff);
ut_ad(page_get_page_no(page_align(ptr))
== 0xffffffff);
break;
case BUF_BLOCK_FILE_PAGE:
ut_ad(block->page.space
== page_get_space_id(page_align(ptr)));
ut_ad(block->page.offset
== page_get_page_no(page_align(ptr)));
break;
}
mutex_exit(&block->mutex);
#endif /* UNIV_DEBUG */
return(block); return(block);
} }
...@@ -2366,8 +2438,8 @@ buf_page_optimistic_get_func( ...@@ -2366,8 +2438,8 @@ buf_page_optimistic_get_func(
buf_block_get_page_no(block), NULL)); buf_block_get_page_no(block), NULL));
if (rw_latch == RW_S_LATCH) { if (rw_latch == RW_S_LATCH) {
success = rw_lock_s_lock_func_nowait(&(block->lock), success = rw_lock_s_lock_nowait(&(block->lock),
file, line); file, line);
fix_type = MTR_MEMO_PAGE_S_FIX; fix_type = MTR_MEMO_PAGE_S_FIX;
} else { } else {
success = rw_lock_x_lock_func_nowait(&(block->lock), success = rw_lock_x_lock_func_nowait(&(block->lock),
...@@ -2478,8 +2550,8 @@ buf_page_get_known_nowait( ...@@ -2478,8 +2550,8 @@ buf_page_get_known_nowait(
ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
if (rw_latch == RW_S_LATCH) { if (rw_latch == RW_S_LATCH) {
success = rw_lock_s_lock_func_nowait(&(block->lock), success = rw_lock_s_lock_nowait(&(block->lock),
file, line); file, line);
fix_type = MTR_MEMO_PAGE_S_FIX; fix_type = MTR_MEMO_PAGE_S_FIX;
} else { } else {
success = rw_lock_x_lock_func_nowait(&(block->lock), success = rw_lock_x_lock_func_nowait(&(block->lock),
...@@ -2556,7 +2628,7 @@ buf_page_try_get_func( ...@@ -2556,7 +2628,7 @@ buf_page_try_get_func(
mutex_exit(&block->mutex); mutex_exit(&block->mutex);
fix_type = MTR_MEMO_PAGE_S_FIX; fix_type = MTR_MEMO_PAGE_S_FIX;
success = rw_lock_s_lock_func_nowait(&block->lock, file, line); success = rw_lock_s_lock_nowait(&block->lock, file, line);
if (!success) { if (!success) {
/* Let us try to get an X-latch. If the current thread /* Let us try to get an X-latch. If the current thread
......
...@@ -1678,6 +1678,8 @@ fil_write_lsn_and_arch_no_to_file( ...@@ -1678,6 +1678,8 @@ fil_write_lsn_and_arch_no_to_file(
fil_write(TRUE, 0, 0, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL); fil_write(TRUE, 0, 0, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
mem_free(buf1);
return(DB_SUCCESS); return(DB_SUCCESS);
} }
......
...@@ -13,6 +13,38 @@ ...@@ -13,6 +13,38 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
/* TODO list for the InnoDB handler in 5.0: /* TODO list for the InnoDB handler in 5.0:
- Remove the flag trx->active_trans and look at trx->conc_state - Remove the flag trx->active_trans and look at trx->conc_state
- fix savepoint functions to use savepoint storage area - fix savepoint functions to use savepoint storage area
...@@ -466,6 +498,8 @@ static SHOW_VAR innodb_status_variables[]= { ...@@ -466,6 +498,8 @@ static SHOW_VAR innodb_status_variables[]= {
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG}, (char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
{"dblwr_writes", {"dblwr_writes",
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG}, (char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
{"have_atomic_builtins",
(char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
{"log_waits", {"log_waits",
(char*) &export_vars.innodb_log_waits, SHOW_LONG}, (char*) &export_vars.innodb_log_waits, SHOW_LONG},
{"log_write_requests", {"log_write_requests",
...@@ -8045,7 +8079,8 @@ innodb_mutex_show_status( ...@@ -8045,7 +8079,8 @@ innodb_mutex_show_status(
stat_print_fn* stat_print) stat_print_fn* stat_print)
{ {
char buf1[IO_SIZE], buf2[IO_SIZE]; char buf1[IO_SIZE], buf2[IO_SIZE];
mutex_t* mutex; mutex_t* mutex;
rw_lock_t* lock;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
ulint rw_lock_count= 0; ulint rw_lock_count= 0;
ulint rw_lock_count_spin_loop= 0; ulint rw_lock_count_spin_loop= 0;
...@@ -8116,6 +8151,29 @@ innodb_mutex_show_status( ...@@ -8116,6 +8151,29 @@ innodb_mutex_show_status(
mutex_exit(&mutex_list_mutex); mutex_exit(&mutex_list_mutex);
mutex_enter(&rw_lock_list_mutex);
lock = UT_LIST_GET_FIRST(rw_lock_list);
while (lock != NULL) {
if (lock->count_os_wait) {
buf1len= my_snprintf(buf1, sizeof(buf1), "%s:%lu",
lock->cfile_name, (ulong) lock->cline);
buf2len= my_snprintf(buf2, sizeof(buf2),
"os_waits=%lu", lock->count_os_wait);
if (stat_print(thd, innobase_hton_name,
hton_name_len, buf1, buf1len,
buf2, buf2len)) {
mutex_exit(&rw_lock_list_mutex);
DBUG_RETURN(1);
}
}
lock = UT_LIST_GET_NEXT(list, lock);
}
mutex_exit(&rw_lock_list_mutex);
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
buf2len= my_snprintf(buf2, sizeof(buf2), buf2len= my_snprintf(buf2, sizeof(buf2),
"count=%lu, spin_waits=%lu, spin_rounds=%lu, " "count=%lu, spin_waits=%lu, spin_rounds=%lu, "
...@@ -8151,56 +8209,35 @@ bool innobase_show_status(handlerton *hton, THD* thd, ...@@ -8151,56 +8209,35 @@ bool innobase_show_status(handlerton *hton, THD* thd,
} }
} }
/**************************************************************************** /****************************************************************************
Handling the shared INNOBASE_SHARE structure that is needed to provide table Handling the shared INNOBASE_SHARE structure that is needed to provide table
locking. locking.
****************************************************************************/ ****************************************************************************/
/****************************************************************************
Folds a string in system_charset_info. */
static
ulint
innobase_fold_name(
/*===============*/
/* out: fold value of the name */
const uchar* name, /* in: string to be folded */
size_t length) /* in: length of the name in bytes */
{
ulong n1 = 1, n2 = 4;
system_charset_info->coll->hash_sort(system_charset_info,
name, length, &n1, &n2);
return((ulint) n1);
}
static INNOBASE_SHARE* get_share(const char* table_name) static INNOBASE_SHARE* get_share(const char* table_name)
{ {
INNOBASE_SHARE *share; INNOBASE_SHARE *share;
pthread_mutex_lock(&innobase_share_mutex); pthread_mutex_lock(&innobase_share_mutex);
uint length=(uint) strlen(table_name);
ulint fold = innobase_fold_name((const uchar*) table_name, length); ulint fold = ut_fold_string(table_name);
HASH_SEARCH(table_name_hash, innobase_open_tables, fold, HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
INNOBASE_SHARE*, share, INNOBASE_SHARE*, share,
ut_ad(share->use_count > 0), ut_ad(share->use_count > 0),
!my_strnncoll(system_charset_info, !strcmp(share->table_name, table_name));
share->table_name,
share->table_name_length,
(const uchar*) table_name, length));
if (!share) { if (!share) {
uint length = (uint) strlen(table_name);
/* TODO: invoke HASH_MIGRATE if innobase_open_tables /* TODO: invoke HASH_MIGRATE if innobase_open_tables
grows too big */ grows too big */
share = (INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1, share = (INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1,
MYF(MY_FAE | MY_ZEROFILL)); MYF(MY_FAE | MY_ZEROFILL));
share->table_name_length = length; share->table_name = (char*) memcpy(share + 1,
share->table_name = (uchar*) memcpy(share + 1, table_name, length + 1);
table_name, length + 1);
HASH_INSERT(INNOBASE_SHARE, table_name_hash, HASH_INSERT(INNOBASE_SHARE, table_name_hash,
innobase_open_tables, fold, share); innobase_open_tables, fold, share);
...@@ -8221,24 +8258,18 @@ static void free_share(INNOBASE_SHARE* share) ...@@ -8221,24 +8258,18 @@ static void free_share(INNOBASE_SHARE* share)
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
INNOBASE_SHARE* share2; INNOBASE_SHARE* share2;
ulint fold = innobase_fold_name(share->table_name, ulint fold = ut_fold_string(share->table_name);
share->table_name_length);
HASH_SEARCH(table_name_hash, innobase_open_tables, fold, HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
INNOBASE_SHARE*, share2, INNOBASE_SHARE*, share2,
ut_ad(share->use_count > 0), ut_ad(share->use_count > 0),
!my_strnncoll(system_charset_info, !strcmp(share->table_name, share2->table_name));
share->table_name,
share->table_name_length,
share2->table_name,
share2->table_name_length));
ut_a(share2 == share); ut_a(share2 == share);
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
if (!--share->use_count) { if (!--share->use_count) {
ulint fold = innobase_fold_name(share->table_name, ulint fold = ut_fold_string(share->table_name);
share->table_name_length);
HASH_DELETE(INNOBASE_SHARE, table_name_hash, HASH_DELETE(INNOBASE_SHARE, table_name_hash,
innobase_open_tables, fold, share); innobase_open_tables, fold, share);
......
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
typedef struct st_innobase_share { typedef struct st_innobase_share {
THR_LOCK lock; THR_LOCK lock;
pthread_mutex_t mutex; pthread_mutex_t mutex;
const uchar *table_name; const char* table_name;
uint table_name_length,use_count; uint use_count;
void* table_name_hash; void* table_name_hash;
} INNOBASE_SHARE; } INNOBASE_SHARE;
......
...@@ -5,6 +5,38 @@ The database buffer buf_pool ...@@ -5,6 +5,38 @@ The database buffer buf_pool
Created 11/5/1995 Heikki Tuuri Created 11/5/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "buf0flu.h" #include "buf0flu.h"
#include "buf0lru.h" #include "buf0lru.h"
...@@ -851,7 +883,7 @@ buf_block_buf_fix_inc_func( ...@@ -851,7 +883,7 @@ buf_block_buf_fix_inc_func(
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ibool ret; ibool ret;
ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line); ret = rw_lock_s_lock_nowait(&(block->debug_latch), file, line);
ut_a(ret); ut_a(ret);
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
ut_ad(mutex_own(&block->mutex)); ut_ad(mutex_own(&block->mutex));
......
...@@ -17,7 +17,6 @@ Created 9/20/1997 Heikki Tuuri ...@@ -17,7 +17,6 @@ Created 9/20/1997 Heikki Tuuri
#ifdef UNIV_HOTBACKUP #ifdef UNIV_HOTBACKUP
extern ibool recv_replay_file_ops; extern ibool recv_replay_file_ops;
#endif /* UNIV_HOTBACKUP */
/*********************************************************************** /***********************************************************************
Reads the checkpoint info needed in hot backup. */ Reads the checkpoint info needed in hot backup. */
...@@ -55,6 +54,7 @@ recv_scan_log_seg_for_backup( ...@@ -55,6 +54,7 @@ recv_scan_log_seg_for_backup(
ulint* n_bytes_scanned);/* out: how much we were able to ulint* n_bytes_scanned);/* out: how much we were able to
scan, smaller than buf_len if log scan, smaller than buf_len if log
data ended here */ data ended here */
#endif /* UNIV_HOTBACKUP */
/*********************************************************************** /***********************************************************************
Returns TRUE if recovery is currently running. */ Returns TRUE if recovery is currently running. */
UNIV_INLINE UNIV_INLINE
......
...@@ -6,6 +6,38 @@ synchronization primitives. ...@@ -6,6 +6,38 @@ synchronization primitives.
Created 9/6/1995 Heikki Tuuri Created 9/6/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#ifndef os0sync_h #ifndef os0sync_h
#define os0sync_h #define os0sync_h
...@@ -261,6 +293,29 @@ os_fast_mutex_free( ...@@ -261,6 +293,29 @@ os_fast_mutex_free(
/*===============*/ /*===============*/
os_fast_mutex_t* fast_mutex); /* in: mutex to free */ os_fast_mutex_t* fast_mutex); /* in: mutex to free */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/**************************************************************
Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins. */
UNIV_INLINE
ibool
os_compare_and_swap(
/*================*/
/* out: true if swapped */
volatile lint* ptr, /* in: pointer to target */
lint oldVal, /* in: value to compare to */
lint newVal); /* in: value to swap in */
/**************************************************************
Atomic increment for InnoDB. Currently requires GCC atomic builtins. */
UNIV_INLINE
lint
os_atomic_increment(
/*================*/
/* out: resulting value */
volatile lint* ptr, /* in: pointer to target */
lint amount); /* in: amount of increment */
#endif /* HAVE_GCC_ATOMIC_BUILTINS */
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "os0sync.ic" #include "os0sync.ic"
#endif #endif
......
...@@ -5,6 +5,38 @@ The interface to the operating system synchronization primitives. ...@@ -5,6 +5,38 @@ The interface to the operating system synchronization primitives.
Created 9/6/1995 Heikki Tuuri Created 9/6/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#ifdef __WIN__ #ifdef __WIN__
#include <winbase.h> #include <winbase.h>
...@@ -44,3 +76,38 @@ os_fast_mutex_trylock( ...@@ -44,3 +76,38 @@ os_fast_mutex_trylock(
#endif #endif
#endif #endif
} }
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/**************************************************************
Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins. */
UNIV_INLINE
ibool
os_compare_and_swap(
/*================*/
/* out: true if swapped */
volatile lint* ptr, /* in: pointer to target */
lint oldVal, /* in: value to compare to */
lint newVal) /* in: value to swap in */
{
if(__sync_bool_compare_and_swap(ptr, oldVal, newVal)) {
return(TRUE);
}
return(FALSE);
}
/**************************************************************
Atomic increment for InnoDB. Currently requires GCC atomic builtins. */
UNIV_INLINE
lint
os_atomic_increment(
/*================*/
/* out: resulting value */
volatile lint* ptr, /* in: pointer to target */
lint amount) /* in: amount of increment */
{
lint newVal = __sync_add_and_fetch(ptr, amount);
return newVal;
}
#endif /* HAVE_GCC_ATOMIC_BUILTINS */
...@@ -5,7 +5,38 @@ The server main program ...@@ -5,7 +5,38 @@ The server main program
Created 10/10/1995 Heikki Tuuri Created 10/10/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#ifndef srv0srv_h #ifndef srv0srv_h
#define srv0srv_h #define srv0srv_h
...@@ -533,6 +564,7 @@ struct export_var_struct{ ...@@ -533,6 +564,7 @@ struct export_var_struct{
ulint innodb_buffer_pool_read_ahead_rnd; ulint innodb_buffer_pool_read_ahead_rnd;
ulint innodb_dblwr_pages_written; ulint innodb_dblwr_pages_written;
ulint innodb_dblwr_writes; ulint innodb_dblwr_writes;
ibool innodb_have_atomic_builtins;
ulint innodb_log_waits; ulint innodb_log_waits;
ulint innodb_log_write_requests; ulint innodb_log_write_requests;
ulint innodb_log_writes; ulint innodb_log_writes;
...@@ -569,4 +601,3 @@ struct srv_sys_struct{ ...@@ -569,4 +601,3 @@ struct srv_sys_struct{
extern ulint srv_n_threads_active[]; extern ulint srv_n_threads_active[];
#endif #endif
...@@ -65,8 +65,7 @@ srv_add_path_separator_if_needed( ...@@ -65,8 +65,7 @@ srv_add_path_separator_if_needed(
char* str); /* in: null-terminated character string */ char* str); /* in: null-terminated character string */
/******************************************************************** /********************************************************************
Starts Innobase and creates a new database if database files Starts Innobase and creates a new database if database files
are not found and the user wants. Server parameters are are not found and the user wants. */
read from a file of name "srv_init" in the ib_home directory. */
UNIV_INTERN UNIV_INTERN
int int
innobase_start_or_create_for_mysql(void); innobase_start_or_create_for_mysql(void);
......
...@@ -5,6 +5,38 @@ The read-write lock (for threads, not for database transactions) ...@@ -5,6 +5,38 @@ The read-write lock (for threads, not for database transactions)
Created 9/11/1995 Heikki Tuuri Created 9/11/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#ifndef sync0rw_h #ifndef sync0rw_h
#define sync0rw_h #define sync0rw_h
...@@ -24,6 +56,12 @@ smaller than 30 and the order of the numerical values like below! */ ...@@ -24,6 +56,12 @@ smaller than 30 and the order of the numerical values like below! */
#define RW_X_LATCH 2 #define RW_X_LATCH 2
#define RW_NO_LATCH 3 #define RW_NO_LATCH 3
/* We decrement lock_word by this amount for each x_lock. It is also the
start value for the lock_word, meaning that it limits the maximum number
of concurrent read locks before the rw_lock breaks. The current value of
0x00100000 allows 1,048,575 concurrent readers and 2047 recursive writers.*/
#define X_LOCK_DECR 0x00100000
typedef struct rw_lock_struct rw_lock_t; typedef struct rw_lock_struct rw_lock_t;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
typedef struct rw_lock_debug_struct rw_lock_debug_t; typedef struct rw_lock_debug_struct rw_lock_debug_t;
...@@ -47,14 +85,14 @@ extern ibool rw_lock_debug_waiters; /* This is set to TRUE, if ...@@ -47,14 +85,14 @@ extern ibool rw_lock_debug_waiters; /* This is set to TRUE, if
there may be waiters for the event */ there may be waiters for the event */
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
extern ulint rw_s_system_call_count; extern ib_int64_t rw_s_spin_wait_count;
extern ulint rw_s_spin_wait_count; extern ib_int64_t rw_s_spin_round_count;
extern ulint rw_s_exit_count; extern ib_int64_t rw_s_exit_count;
extern ulint rw_s_os_wait_count; extern ib_int64_t rw_s_os_wait_count;
extern ulint rw_x_system_call_count; extern ib_int64_t rw_x_spin_wait_count;
extern ulint rw_x_spin_wait_count; extern ib_int64_t rw_x_spin_round_count;
extern ulint rw_x_os_wait_count; extern ib_int64_t rw_x_os_wait_count;
extern ulint rw_x_exit_count; extern ib_int64_t rw_x_exit_count;
/********************************************************************** /**********************************************************************
Creates, or rather, initializes an rw-lock object in a specified memory Creates, or rather, initializes an rw-lock object in a specified memory
...@@ -127,8 +165,22 @@ corresponding function. */ ...@@ -127,8 +165,22 @@ corresponding function. */
NOTE! The following macros should be used in rw s-locking, not the NOTE! The following macros should be used in rw s-locking, not the
corresponding function. */ corresponding function. */
#define rw_lock_s_lock_nowait(M) rw_lock_s_lock_func_nowait(\ #define rw_lock_s_lock_nowait(M, F, L) rw_lock_s_lock_low(\
(M), __FILE__, __LINE__) (M), 0, (F), (L))
/**********************************************************************
Low-level function which tries to lock an rw-lock in s-mode. Performs no
spinning. */
UNIV_INLINE
ibool
rw_lock_s_lock_low(
/*===============*/
/* out: TRUE if success */
rw_lock_t* lock, /* in: pointer to rw-lock */
ulint pass __attribute__((unused)),
/* in: pass value; != 0, if the lock will be
passed to another thread to unlock */
const char* file_name, /* in: file name where lock requested */
ulint line); /* in: line where requested */
/********************************************************************** /**********************************************************************
NOTE! Use the corresponding macro, not directly this function, except if NOTE! Use the corresponding macro, not directly this function, except if
you supply the file name and line number. Lock an rw-lock in shared mode you supply the file name and line number. Lock an rw-lock in shared mode
...@@ -146,18 +198,6 @@ rw_lock_s_lock_func( ...@@ -146,18 +198,6 @@ rw_lock_s_lock_func(
const char* file_name,/* in: file name where lock requested */ const char* file_name,/* in: file name where lock requested */
ulint line); /* in: line where requested */ ulint line); /* in: line where requested */
/********************************************************************** /**********************************************************************
NOTE! Use the corresponding macro, not directly this function, except if
you supply the file name and line number. Lock an rw-lock in shared mode
for the current thread if the lock can be acquired immediately. */
UNIV_INLINE
ibool
rw_lock_s_lock_func_nowait(
/*=======================*/
/* out: TRUE if success */
rw_lock_t* lock, /* in: pointer to rw-lock */
const char* file_name,/* in: file name where lock requested */
ulint line); /* in: line where requested */
/**********************************************************************
NOTE! Use the corresponding macro, not directly this function! Lock an NOTE! Use the corresponding macro, not directly this function! Lock an
rw-lock in exclusive mode for the current thread if the lock can be rw-lock in exclusive mode for the current thread if the lock can be
obtained immediately. */ obtained immediately. */
...@@ -341,6 +381,41 @@ ulint ...@@ -341,6 +381,41 @@ ulint
rw_lock_get_reader_count( rw_lock_get_reader_count(
/*=====================*/ /*=====================*/
rw_lock_t* lock); rw_lock_t* lock);
/**********************************************************************
Decrements lock_word the specified amount if it is greater than 0.
This is used by both s_lock and x_lock operations. */
UNIV_INLINE
ibool
rw_lock_lock_word_decr(
/*===================*/
/* out: TRUE if decr occurs */
rw_lock_t* lock, /* in: rw-lock */
ulint amount); /* in: amount to decrement */
/**********************************************************************
Increments lock_word the specified amount and returns new value. */
UNIV_INLINE
lint
rw_lock_lock_word_incr(
/*===================*/
/* out: TRUE if decr occurs */
rw_lock_t* lock,
ulint amount); /* in: rw-lock */
/**********************************************************************
This function sets the lock->writer_thread and lock->recursive fields.
For platforms where we are using atomic builtins instead of lock->mutex
it sets the lock->writer_thread field using atomics to ensure memory
ordering. Note that it is assumed that the caller of this function
effectively owns the lock i.e.: nobody else is allowed to modify
lock->writer_thread at this point in time.
The protocol is that lock->writer_thread MUST be updated BEFORE the
lock->recursive flag is set. */
UNIV_INLINE
void
rw_lock_set_writer_id_and_recursion_flag(
/*=====================================*/
rw_lock_t* lock, /* in/out: lock to work on */
ibool recursive); /* in: TRUE if recursion
allowed */
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
/********************************************************************** /**********************************************************************
Checks if the thread has locked the rw-lock in the specified mode, with Checks if the thread has locked the rw-lock in the specified mode, with
...@@ -417,44 +492,37 @@ Do not use its fields directly! The structure used in the spin lock ...@@ -417,44 +492,37 @@ 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 implementation of a read-write lock. Several threads may have a shared lock
simultaneously in this lock, but only one writer may have an exclusive lock, simultaneously in this lock, but only one writer may have an exclusive lock,
in which case no shared locks are allowed. To prevent starving of a writer in which case no shared locks are allowed. To prevent starving of a writer
blocked by readers, a writer may queue for the lock by setting the writer blocked by readers, a writer may queue for x-lock by decrementing lock_word:
field. Then no new readers are allowed in. */ no new readers will be let in while the thread waits for readers to exit. */
struct rw_lock_struct { struct rw_lock_struct {
volatile lint lock_word;
/* Holds the state of the lock. */
volatile ulint waiters;/* 1: there are waiters */
volatile ibool recursive;/* Default value FALSE which means the lock
is non-recursive. The value is typically set
to TRUE making normal rw_locks recursive. In
case of asynchronous IO, when a non-zero
value of 'pass' is passed then we keep the
lock non-recursive.
This flag also tells us about the state of
writer_thread field. If this flag is set
then writer_thread MUST contain the thread
id of the current x-holder or wait-x thread.
This flag must be reset in x_unlock
functions before incrementing the lock_word */
volatile os_thread_id_t writer_thread;
/* Thread id of writer thread. Is only
guaranteed to have sane and non-stale
value iff recursive flag is set. */
os_event_t event; /* Used by sync0arr.c for thread queueing */ os_event_t event; /* Used by sync0arr.c for thread queueing */
os_event_t wait_ex_event;
#ifdef __WIN__ /* Event for next-writer to wait on. A thread
os_event_t wait_ex_event; /* This windows specific event is must decrement lock_word before waiting. */
used by the thread which has set the #ifndef INNODB_RW_LOCKS_USE_ATOMICS
lock state to RW_LOCK_WAIT_EX. The
rw_lock design guarantees that this
thread will be the next one to proceed
once the current the event gets
signalled. See LEMMA 2 in sync0sync.c */
#endif
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
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;
/* Thread id of a possible writer thread */
ulint writer_count; /* Number of times the same thread has
recursively locked the lock in the exclusive
mode */
mutex_t mutex; /* The mutex protecting rw_lock_struct */ mutex_t mutex; /* The mutex protecting rw_lock_struct */
ulint pass; /* Default value 0. This is set to some #endif /* INNODB_RW_LOCKS_USE_ATOMICS */
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. */
UT_LIST_NODE_T(rw_lock_t) list; UT_LIST_NODE_T(rw_lock_t) list;
/* All allocated rw locks are put into a /* All allocated rw locks are put into a
list */ list */
...@@ -464,7 +532,9 @@ struct rw_lock_struct { ...@@ -464,7 +532,9 @@ struct rw_lock_struct {
info list of the lock */ info list of the lock */
ulint level; /* Level in the global latching order. */ ulint level; /* Level in the global latching order. */
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
ulint count_os_wait; /* Count of os_waits. May not be accurate */
const char* cfile_name;/* File name where lock created */ const char* cfile_name;/* File name where lock created */
/* last s-lock file/line is not guaranteed to be correct */
const char* last_s_file_name;/* File name where last s-locked */ const char* last_s_file_name;/* File name where last s-locked */
const char* last_x_file_name;/* File name where last x-locked */ const char* last_x_file_name;/* File name where last x-locked */
ibool writer_is_wait_ex; ibool writer_is_wait_ex;
......
...@@ -5,6 +5,38 @@ The read-write lock (for threads) ...@@ -5,6 +5,38 @@ The read-write lock (for threads)
Created 9/11/1995 Heikki Tuuri Created 9/11/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
/********************************************************************** /**********************************************************************
Lock an rw-lock in shared mode for the current thread. If the rw-lock is Lock an rw-lock in shared mode for the current thread. If the rw-lock is
...@@ -49,53 +81,88 @@ UNIV_INLINE ...@@ -49,53 +81,88 @@ UNIV_INLINE
ulint ulint
rw_lock_get_waiters( rw_lock_get_waiters(
/*================*/ /*================*/
rw_lock_t* lock) /* out: 1 if waiters, 0 otherwise */
rw_lock_t* lock) /* in: rw-lock */
{ {
return(lock->waiters); return(lock->waiters);
} }
/************************************************************************
Sets lock->waiters to 1. It is not an error if lock->waiters is already
1. On platforms where ATOMIC builtins are used this function enforces a
memory barrier. */
UNIV_INLINE UNIV_INLINE
void void
rw_lock_set_waiters( rw_lock_set_waiter_flag(
/*================*/ /*====================*/
rw_lock_t* lock, rw_lock_t* lock) /* in: rw-lock */
ulint flag)
{ {
lock->waiters = flag; #ifdef INNODB_RW_LOCKS_USE_ATOMICS
os_compare_and_swap((lint*)&(lock->waiters), 0, 1);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 1;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
} }
/************************************************************************
Resets lock->waiters to 0. It is not an error if lock->waiters is already
0. On platforms where ATOMIC builtins are used this function enforces a
memory barrier. */
UNIV_INLINE UNIV_INLINE
ulint void
rw_lock_get_writer( rw_lock_reset_waiter_flag(
/*===============*/ /*======================*/
rw_lock_t* lock) rw_lock_t* lock) /* in: rw-lock */
{ {
return(lock->writer); #ifdef INNODB_RW_LOCKS_USE_ATOMICS
os_compare_and_swap((lint*)&(lock->waiters), 1, 0);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 0;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
} }
/**********************************************************************
Returns the write-status of the lock - this function made more sense
with the old rw_lock implementation. */
UNIV_INLINE UNIV_INLINE
void ulint
rw_lock_set_writer( rw_lock_get_writer(
/*===============*/ /*===============*/
rw_lock_t* lock, rw_lock_t* lock)
ulint flag)
{ {
lock->writer = flag; lint lock_word = lock->lock_word;
if(lock_word > 0) {
/* return NOT_LOCKED in s-lock state, like the writer
member of the old lock implementation. */
return(RW_LOCK_NOT_LOCKED);
} else if (((-lock_word) % X_LOCK_DECR) == 0) {
return(RW_LOCK_EX);
} else {
ut_ad(lock_word > -X_LOCK_DECR);
return(RW_LOCK_WAIT_EX);
}
} }
/**********************************************************************
Returns number of readers. */
UNIV_INLINE UNIV_INLINE
ulint ulint
rw_lock_get_reader_count( rw_lock_get_reader_count(
/*=====================*/ /*=====================*/
rw_lock_t* lock) rw_lock_t* lock)
{ {
return(lock->reader_count); lint lock_word = lock->lock_word;
} if(lock_word > 0) {
UNIV_INLINE /* s-locked, no x-waiters */
void return(X_LOCK_DECR - lock_word);
rw_lock_set_reader_count( } else if (lock_word < 0 && lock_word > -X_LOCK_DECR) {
/*=====================*/ /* s-locked, with x-waiters */
rw_lock_t* lock, return((ulint)(-lock_word));
ulint count) }
{ return(0);
lock->reader_count = count;
} }
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
UNIV_INLINE UNIV_INLINE
mutex_t* mutex_t*
rw_lock_get_mutex( rw_lock_get_mutex(
...@@ -104,6 +171,7 @@ rw_lock_get_mutex( ...@@ -104,6 +171,7 @@ rw_lock_get_mutex(
{ {
return(&(lock->mutex)); return(&(lock->mutex));
} }
#endif
/********************************************************************** /**********************************************************************
Returns the value of writer_count for the lock. Does not reserve the lock Returns the value of writer_count for the lock. Does not reserve the lock
...@@ -115,7 +183,127 @@ rw_lock_get_x_lock_count( ...@@ -115,7 +183,127 @@ rw_lock_get_x_lock_count(
/* out: value of writer_count */ /* out: value of writer_count */
rw_lock_t* lock) /* in: rw-lock */ rw_lock_t* lock) /* in: rw-lock */
{ {
return(lock->writer_count); lint lock_copy = lock->lock_word;
/* If there is a reader, lock_word is not divisible by X_LOCK_DECR */
if(lock_copy > 0 || (-lock_copy) % X_LOCK_DECR != 0) {
return(0);
}
return(((-lock_copy) / X_LOCK_DECR) + 1);
}
/**********************************************************************
Two different implementations for decrementing the lock_word of a rw_lock:
one for systems supporting atomic operations, one for others. This does
does not support recusive x-locks: they should be handled by the caller and
need not be atomic since they are performed by the current lock holder.
Returns true if the decrement was made, false if not. */
UNIV_INLINE
ibool
rw_lock_lock_word_decr(
/*===================*/
/* out: TRUE if decr occurs */
rw_lock_t* lock, /* in: rw-lock */
ulint amount) /* in: amount of decrement */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
lint local_lock_word = lock->lock_word;
while (local_lock_word > 0) {
if(os_compare_and_swap(&(lock->lock_word),
local_lock_word,
local_lock_word - amount)) {
return(TRUE);
}
local_lock_word = lock->lock_word;
}
return(FALSE);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
ibool success = FALSE;
mutex_enter(&(lock->mutex));
if(lock->lock_word > 0) {
lock->lock_word -= amount;
success = TRUE;
}
mutex_exit(&(lock->mutex));
return(success);
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
}
/**********************************************************************
Two different implementations for incrementing the lock_word of a rw_lock:
one for systems supporting atomic operations, one for others.
Returns the value of lock_word after increment. */
UNIV_INLINE
lint
rw_lock_lock_word_incr(
/*===================*/
/* out: lock->lock_word after increment */
rw_lock_t* lock, /* in: rw-lock */
ulint amount) /* in: amount of increment */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
return(os_atomic_increment(&(lock->lock_word), amount));
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lint local_lock_word;
mutex_enter(&(lock->mutex));
lock->lock_word += amount;
local_lock_word = lock->lock_word;
mutex_exit(&(lock->mutex));
return(local_lock_word);
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
}
/**********************************************************************
This function sets the lock->writer_thread and lock->recursive fields.
For platforms where we are using atomic builtins instead of lock->mutex
it sets the lock->writer_thread field using atomics to ensure memory
ordering. Note that it is assumed that the caller of this function
effectively owns the lock i.e.: nobody else is allowed to modify
lock->writer_thread at this point in time.
The protocol is that lock->writer_thread MUST be updated BEFORE the
lock->recursive flag is set. */
UNIV_INLINE
void
rw_lock_set_writer_id_and_recursion_flag(
/*=====================================*/
rw_lock_t* lock, /* in/out: lock to work on */
ibool recursive) /* in: TRUE if recursion
allowed */
{
os_thread_id_t curr_thread = os_thread_get_curr_id();
ut_ad(lock);
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
os_thread_id_t local_thread = lock->writer_thread;
ibool success = os_compare_and_swap((lint*)&(lock->writer_thread),
(lint)local_thread,
(lint)curr_thread);
ut_a(success);
lock->recursive = recursive;
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
mutex_enter(&lock->mutex);
lock->writer_thread = curr_thread;
lock->recursive = recursive;
mutex_exit(&lock->mutex);
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
} }
/********************************************************************** /**********************************************************************
...@@ -133,25 +321,21 @@ rw_lock_s_lock_low( ...@@ -133,25 +321,21 @@ rw_lock_s_lock_low(
const char* file_name, /* in: file name where lock requested */ const char* file_name, /* in: file name where lock requested */
ulint line) /* in: line where requested */ ulint line) /* in: line where requested */
{ {
ut_ad(mutex_own(rw_lock_get_mutex(lock))); /* TODO: study performance of UNIV_LIKELY branch prediction hints. */
if (!rw_lock_lock_word_decr(lock, 1)) {
/* Check if the writer field is free */ /* Locking did not succeed */
return(FALSE);
if (UNIV_LIKELY(lock->writer == RW_LOCK_NOT_LOCKED)) { }
/* Set the shared lock by incrementing the reader count */
lock->reader_count++;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name, rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name, line);
line);
#endif #endif
lock->last_s_file_name = file_name; /* These debugging values are not set safely: they may be incorrect
lock->last_s_line = line; or even refer to a line that is invalid for the file name. */
lock->last_s_file_name = file_name;
return(TRUE); /* locking succeeded */ lock->last_s_line = line;
}
return(FALSE); /* locking did not succeed */ return(TRUE); /* locking succeeded */
} }
/********************************************************************** /**********************************************************************
...@@ -166,11 +350,10 @@ rw_lock_s_lock_direct( ...@@ -166,11 +350,10 @@ rw_lock_s_lock_direct(
const char* file_name, /* in: file name where requested */ const char* file_name, /* in: file name where requested */
ulint line) /* in: line where lock requested */ ulint line) /* in: line where lock requested */
{ {
ut_ad(lock->writer == RW_LOCK_NOT_LOCKED); ut_ad(lock->lock_word == X_LOCK_DECR);
ut_ad(rw_lock_get_reader_count(lock) == 0);
/* Set the shared lock by incrementing the reader count */ /* Indicate there is a new reader by decrementing lock_word */
lock->reader_count++; lock->lock_word--;
lock->last_s_file_name = file_name; lock->last_s_file_name = file_name;
lock->last_s_line = line; lock->last_s_line = line;
...@@ -193,13 +376,11 @@ rw_lock_x_lock_direct( ...@@ -193,13 +376,11 @@ rw_lock_x_lock_direct(
ulint line) /* in: line where lock requested */ ulint line) /* in: line where lock requested */
{ {
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
ut_ad(rw_lock_get_reader_count(lock) == 0); ut_ad(lock->lock_word == X_LOCK_DECR);
ut_ad(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
rw_lock_set_writer(lock, RW_LOCK_EX); lock->lock_word -= X_LOCK_DECR;
lock->writer_thread = os_thread_get_curr_id(); lock->writer_thread = os_thread_get_curr_id();
lock->writer_count++; lock->recursive = TRUE;
lock->pass = 0;
lock->last_x_file_name = file_name; lock->last_x_file_name = file_name;
lock->last_x_line = line; lock->last_x_line = line;
...@@ -240,15 +421,12 @@ rw_lock_s_lock_func( ...@@ -240,15 +421,12 @@ rw_lock_s_lock_func(
ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */ ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
mutex_enter(rw_lock_get_mutex(lock)); /* TODO: study performance of UNIV_LIKELY branch prediction hints. */
if (rw_lock_s_lock_low(lock, pass, file_name, line)) {
if (UNIV_LIKELY(rw_lock_s_lock_low(lock, pass, file_name, line))) {
mutex_exit(rw_lock_get_mutex(lock));
return; /* Success */ return; /* Success */
} else { } else {
/* Did not succeed, try spin wait */ /* Did not succeed, try spin wait */
mutex_exit(rw_lock_get_mutex(lock));
rw_lock_s_lock_spin(lock, pass, file_name, line); rw_lock_s_lock_spin(lock, pass, file_name, line);
...@@ -258,86 +436,60 @@ rw_lock_s_lock_func( ...@@ -258,86 +436,60 @@ rw_lock_s_lock_func(
/********************************************************************** /**********************************************************************
NOTE! Use the corresponding macro, not directly this function! Lock an NOTE! Use the corresponding macro, not directly this function! Lock an
rw-lock in shared mode for the current thread if the lock can be acquired rw-lock in exclusive mode for the current thread if the lock can be
immediately. */ obtained immediately. */
UNIV_INLINE UNIV_INLINE
ibool ibool
rw_lock_s_lock_func_nowait( rw_lock_x_lock_func_nowait(
/*=======================*/ /*=======================*/
/* out: TRUE if success */ /* out: TRUE if success */
rw_lock_t* lock, /* in: pointer to rw-lock */ rw_lock_t* lock, /* in: pointer to rw-lock */
const char* file_name,/* in: file name where lock requested */ const char* file_name,/* in: file name where lock requested */
ulint line) /* in: line where requested */ ulint line) /* in: line where requested */
{ {
ibool success = FALSE; os_thread_id_t curr_thread = os_thread_get_curr_id();
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++;
#ifdef UNIV_SYNC_DEBUG ibool success;
rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name,
line);
#endif
lock->last_s_file_name = file_name; #ifdef INNODB_RW_LOCKS_USE_ATOMICS
lock->last_s_line = line; success = os_compare_and_swap(&(lock->lock_word), X_LOCK_DECR, 0);
#else
success = FALSE;
mutex_enter(&(lock->mutex));
if (lock->lock_word == X_LOCK_DECR) {
lock->lock_word = 0;
success = TRUE; success = TRUE;
} }
mutex_exit(&(lock->mutex));
mutex_exit(rw_lock_get_mutex(lock)); #endif
if (success) {
return(success); rw_lock_set_writer_id_and_recursion_flag(lock, TRUE);
}
/********************************************************************** } else if (lock->recursive &&
NOTE! Use the corresponding macro, not directly this function! Lock an os_thread_eq(lock->writer_thread, curr_thread)) {
rw-lock in exclusive mode for the current thread if the lock can be /* Relock: this lock_word modification is safe since no other
obtained immediately. */ threads can modify (lock, unlock, or reserve) lock_word while
UNIV_INLINE there is an exclusive writer and this is the writer thread. */
ibool lock->lock_word -= X_LOCK_DECR;
rw_lock_x_lock_func_nowait(
/*=======================*/
/* out: TRUE if success */
rw_lock_t* lock, /* in: pointer to rw-lock */
const char* file_name,/* in: file name where lock requested */
ulint line) /* in: line where requested */
{
ibool success = FALSE;
os_thread_id_t curr_thread = os_thread_get_curr_id();
mutex_enter(rw_lock_get_mutex(lock));
if (UNIV_UNLIKELY(rw_lock_get_reader_count(lock) != 0)) { ut_ad(((-lock->lock_word) % X_LOCK_DECR) == 0);
} else if (UNIV_LIKELY(rw_lock_get_writer(lock)
== RW_LOCK_NOT_LOCKED)) {
rw_lock_set_writer(lock, RW_LOCK_EX);
lock->writer_thread = curr_thread;
lock->pass = 0;
relock:
lock->writer_count++;
} else {
/* Failure */
return(FALSE);
}
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line); rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
#endif #endif
lock->last_x_file_name = file_name; lock->last_x_file_name = file_name;
lock->last_x_line = line; lock->last_x_line = line;
success = TRUE;
} else if (rw_lock_get_writer(lock) == RW_LOCK_EX
&& lock->pass == 0
&& os_thread_eq(lock->writer_thread, curr_thread)) {
goto relock;
}
mutex_exit(rw_lock_get_mutex(lock));
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
return(success); return(TRUE);
} }
/********************************************************************** /**********************************************************************
...@@ -353,39 +505,21 @@ rw_lock_s_unlock_func( ...@@ -353,39 +505,21 @@ rw_lock_s_unlock_func(
#endif #endif
) )
{ {
mutex_t* mutex = &(lock->mutex); ut_ad((lock->lock_word % X_LOCK_DECR) != 0);
ibool sg = FALSE;
/* Acquire the mutex protecting the rw-lock fields */
mutex_enter(mutex);
/* Reset the shared lock by decrementing the reader count */
ut_a(lock->reader_count > 0);
lock->reader_count--;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED); rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);
#endif #endif
/* If there may be waiters and this was the last s-lock, /* Increment lock_word to indicate 1 less reader */
signal the object */ if (rw_lock_lock_word_incr(lock, 1) == 0) {
if (UNIV_UNLIKELY(lock->waiters)
&& lock->reader_count == 0) {
sg = TRUE;
rw_lock_set_waiters(lock, 0); /* wait_ex waiter exists. It may not be asleep, but we signal
} anyway. We do not wake other waiters, because they can't
exist without wait_ex waiter and wait_ex waiter goes first.*/
mutex_exit(mutex);
if (UNIV_UNLIKELY(sg)) {
#ifdef __WIN__
os_event_set(lock->wait_ex_event); os_event_set(lock->wait_ex_event);
#endif
os_event_set(lock->event);
sync_array_object_signalled(sync_primary_wait_array); sync_array_object_signalled(sync_primary_wait_array);
} }
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
...@@ -404,16 +538,15 @@ rw_lock_s_unlock_direct( ...@@ -404,16 +538,15 @@ rw_lock_s_unlock_direct(
/*====================*/ /*====================*/
rw_lock_t* lock) /* in: rw-lock */ rw_lock_t* lock) /* in: rw-lock */
{ {
/* Reset the shared lock by decrementing the reader count */ ut_ad(lock->lock_word < X_LOCK_DECR);
ut_ad(lock->reader_count > 0);
lock->reader_count--;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED); rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);
#endif #endif
/* Decrease reader count by incrementing lock_word */
lock->lock_word++;
ut_ad(!lock->waiters); ut_ad(!lock->waiters);
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
#ifdef UNIV_SYNC_PERF_STAT #ifdef UNIV_SYNC_PERF_STAT
...@@ -434,42 +567,32 @@ rw_lock_x_unlock_func( ...@@ -434,42 +567,32 @@ rw_lock_x_unlock_func(
#endif #endif
) )
{ {
ibool sg = FALSE; ut_ad((lock->lock_word % X_LOCK_DECR) == 0);
/* Acquire the mutex protecting the rw-lock fields */ /* lock->recursive flag also indicates if lock->writer_thread is
mutex_enter(&(lock->mutex)); valid or stale. If we are the last of the recursive callers
then we must unset lock->recursive flag to indicate that the
/* Reset the exclusive lock if this thread no longer has an x-mode lock->writer_thread is now stale.
lock */ Note that since we still hold the x-lock we can safely read the
lock_word. */
ut_ad(lock->writer_count > 0); if (lock->lock_word == 0) {
/* Last caller in a possible recursive chain. */
lock->writer_count--; lock->recursive = FALSE;
if (lock->writer_count == 0) {
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
} }
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX); rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
#endif #endif
/* If there may be waiters, signal the lock */ if (rw_lock_lock_word_incr(lock, X_LOCK_DECR) == X_LOCK_DECR) {
if (UNIV_UNLIKELY(lock->waiters) /* Lock is now free. May have to signal read/write waiters.
&& lock->writer_count == 0) { We do not need to signal wait_ex waiters, since they cannot
exist when there is a writer. */
sg = TRUE; if (lock->waiters) {
rw_lock_set_waiters(lock, 0); rw_lock_reset_waiter_flag(lock);
} os_event_set(lock->event);
sync_array_object_signalled(sync_primary_wait_array);
mutex_exit(&(lock->mutex)); }
if (UNIV_UNLIKELY(sg)) {
#ifdef __WIN__
os_event_set(lock->wait_ex_event);
#endif
os_event_set(lock->event);
sync_array_object_signalled(sync_primary_wait_array);
} }
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
...@@ -481,7 +604,7 @@ rw_lock_x_unlock_func( ...@@ -481,7 +604,7 @@ rw_lock_x_unlock_func(
/********************************************************************** /**********************************************************************
Releases an exclusive mode lock when we know there are no waiters, and Releases an exclusive mode lock when we know there are no waiters, and
none else will access the lock durint the time this function is executed. */ none else will access the lock during the time this function is executed. */
UNIV_INLINE UNIV_INLINE
void void
rw_lock_x_unlock_direct( rw_lock_x_unlock_direct(
...@@ -491,18 +614,18 @@ rw_lock_x_unlock_direct( ...@@ -491,18 +614,18 @@ rw_lock_x_unlock_direct(
/* Reset the exclusive lock if this thread no longer has an x-mode /* Reset the exclusive lock if this thread no longer has an x-mode
lock */ lock */
ut_ad(lock->writer_count > 0); ut_ad((lock->lock_word % X_LOCK_DECR) == 0);
lock->writer_count--;
if (lock->writer_count == 0) {
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
}
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX); rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
#endif #endif
if (lock->lock_word == 0) {
lock->recursive = FALSE;
}
lock->lock_word += X_LOCK_DECR;
ut_ad(!lock->waiters); ut_ad(!lock->waiters);
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
......
...@@ -5,6 +5,38 @@ Mutex, the basic synchronization primitive ...@@ -5,6 +5,38 @@ Mutex, the basic synchronization primitive
Created 9/5/1995 Heikki Tuuri Created 9/5/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#ifndef sync0sync_h #ifndef sync0sync_h
#define sync0sync_h #define sync0sync_h
...@@ -237,7 +269,7 @@ mutex_n_reserved(void); ...@@ -237,7 +269,7 @@ mutex_n_reserved(void);
NOT to be used outside this module except in debugging! Gets the value NOT to be used outside this module except in debugging! Gets the value
of the lock word. */ of the lock word. */
UNIV_INLINE UNIV_INLINE
ulint byte
mutex_get_lock_word( mutex_get_lock_word(
/*================*/ /*================*/
const mutex_t* mutex); /* in: mutex */ const mutex_t* mutex); /* in: mutex */
...@@ -463,9 +495,11 @@ implementation of a mutual exclusion semaphore. */ ...@@ -463,9 +495,11 @@ implementation of a mutual exclusion semaphore. */
struct mutex_struct { struct mutex_struct {
os_event_t event; /* Used by sync0arr.c for the wait queue */ os_event_t event; /* Used by sync0arr.c for the wait queue */
ulint lock_word; /* This ulint is the target of the atomic byte lock_word; /* This byte is the target of the atomic
test-and-set instruction in Win32 */ test-and-set instruction in Win32 and
#if defined WIN32 && defined UNIV_CAN_USE_X86_ASSEMBLER x86 32/64 with GCC 4.1.0 or later version */
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
#else #else
os_fast_mutex_t os_fast_mutex_t
os_fast_mutex; /* In other systems we use this OS mutex os_fast_mutex; /* In other systems we use this OS mutex
...@@ -519,8 +553,7 @@ to 20 microseconds. */ ...@@ -519,8 +553,7 @@ to 20 microseconds. */
/* The number of system calls made in this module. Intended for performance /* The number of system calls made in this module. Intended for performance
monitoring. */ monitoring. */
extern ulint mutex_system_call_count; extern ib_int64_t mutex_exit_count;
extern ulint mutex_exit_count;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
/* Latching order checks start when this is set TRUE */ /* Latching order checks start when this is set TRUE */
......
...@@ -5,16 +5,38 @@ Mutex, the basic synchronization primitive ...@@ -5,16 +5,38 @@ Mutex, the basic synchronization primitive
Created 9/5/1995 Heikki Tuuri Created 9/5/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
#if defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86) # Copyright (c) 2008, Google Inc.
/* %z0: Use the size of operand %0 which in our case is *m to determine # All rights reserved.
instruction size, it should end up as xchgl. "1" in the input constraint, #
says that "in" has to go in the same place as "out".*/ # Redistribution and use in source and binary forms, with or without
#define TAS(m, in, out) \ # modification, are permitted provided that the following conditions
asm volatile ("xchg%z0 %2, %0" \ # are met:
: "=g" (*(m)), "=r" (out) \ # * Redistributions of source code must retain the above copyright
: "1" (in)) /* Note: "1" here refers to "=r" (out) */ # notice, this list of conditions and the following disclaimer.
#endif # * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
/********************************************************************** /**********************************************************************
Sets the waiters field in a mutex. */ Sets the waiters field in a mutex. */
...@@ -59,7 +81,7 @@ mutex_signal_object( ...@@ -59,7 +81,7 @@ mutex_signal_object(
Performs an atomic test-and-set instruction to the lock_word field of a Performs an atomic test-and-set instruction to the lock_word field of a
mutex. */ mutex. */
UNIV_INLINE UNIV_INLINE
ulint byte
mutex_test_and_set( mutex_test_and_set(
/*===============*/ /*===============*/
/* out: the previous value of lock_word: 0 or /* out: the previous value of lock_word: 0 or
...@@ -67,18 +89,18 @@ mutex_test_and_set( ...@@ -67,18 +89,18 @@ mutex_test_and_set(
mutex_t* mutex) /* in: mutex */ mutex_t* mutex) /* in: mutex */
{ {
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER) #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
ulint res; byte res;
ulint* lw; /* assembler code is used to ensure that byte* lw; /* assembler code is used to ensure that
lock_word is loaded from memory */ lock_word is loaded from memory */
ut_ad(mutex); ut_ad(mutex);
ut_ad(sizeof(ulint) == 4); ut_ad(sizeof(byte) == 1);
lw = &(mutex->lock_word); lw = &(mutex->lock_word);
__asm MOV ECX, lw __asm MOV ECX, lw
__asm MOV EDX, 1 __asm MOV EDX, 1
__asm XCHG EDX, DWORD PTR [ECX] __asm XCHG DL, BYTE PTR [ECX]
__asm MOV res, EDX __asm MOV res, DL
/* The fence below would prevent this thread from /* The fence below would prevent this thread from
reading the data structure protected by the mutex reading the data structure protected by the mutex
...@@ -98,12 +120,8 @@ mutex_test_and_set( ...@@ -98,12 +120,8 @@ mutex_test_and_set(
/* mutex_fence(); */ /* mutex_fence(); */
return(res); return(res);
#elif defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86) #elif defined(HAVE_GCC_ATOMIC_BUILTINS)
ulint res; return __sync_lock_test_and_set(&(mutex->lock_word), 1);
TAS(&mutex->lock_word, 1, res);
return(res);
#else #else
ibool ret; ibool ret;
...@@ -117,7 +135,7 @@ mutex_test_and_set( ...@@ -117,7 +135,7 @@ mutex_test_and_set(
mutex->lock_word = 1; mutex->lock_word = 1;
} }
return(ret); return((byte)ret);
#endif #endif
} }
...@@ -131,7 +149,7 @@ mutex_reset_lock_word( ...@@ -131,7 +149,7 @@ mutex_reset_lock_word(
mutex_t* mutex) /* in: mutex */ mutex_t* mutex) /* in: mutex */
{ {
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER) #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
ulint* lw; /* assembler code is used to ensure that byte* lw; /* assembler code is used to ensure that
lock_word is loaded from memory */ lock_word is loaded from memory */
ut_ad(mutex); ut_ad(mutex);
...@@ -139,11 +157,12 @@ mutex_reset_lock_word( ...@@ -139,11 +157,12 @@ mutex_reset_lock_word(
__asm MOV EDX, 0 __asm MOV EDX, 0
__asm MOV ECX, lw __asm MOV ECX, lw
__asm XCHG EDX, DWORD PTR [ECX] __asm XCHG DL, BYTE PTR [ECX]
#elif defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86) #elif defined(HAVE_GCC_ATOMIC_BUILTINS)
ulint res; /* In theory __sync_lock_release should be used to release the lock.
Unfortunately, it does not work properly alone. The workaround is
TAS(&mutex->lock_word, 0, res); that more conservative __sync_lock_test_and_set is used instead. */
__sync_lock_test_and_set(&(mutex->lock_word), 0);
#else #else
mutex->lock_word = 0; mutex->lock_word = 0;
...@@ -154,12 +173,12 @@ mutex_reset_lock_word( ...@@ -154,12 +173,12 @@ mutex_reset_lock_word(
/********************************************************************** /**********************************************************************
Gets the value of the lock word. */ Gets the value of the lock word. */
UNIV_INLINE UNIV_INLINE
ulint byte
mutex_get_lock_word( mutex_get_lock_word(
/*================*/ /*================*/
const mutex_t* mutex) /* in: mutex */ const mutex_t* mutex) /* in: mutex */
{ {
const volatile ulint* ptr; /* declared volatile to ensure that const volatile byte* ptr; /* declared volatile to ensure that
lock_word is loaded from memory */ lock_word is loaded from memory */
ut_ad(mutex); ut_ad(mutex);
......
...@@ -5,6 +5,38 @@ Version control for database, common definitions, and include files ...@@ -5,6 +5,38 @@ Version control for database, common definitions, and include files
Created 1/20/1994 Heikki Tuuri Created 1/20/1994 Heikki Tuuri
****************************************************************************/ ****************************************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#ifndef univ_i #ifndef univ_i
#define univ_i #define univ_i
...@@ -90,6 +122,13 @@ of the 32-bit x86 assembler in mutex operations. */ ...@@ -90,6 +122,13 @@ of the 32-bit x86 assembler in mutex operations. */
# define UNIV_CAN_USE_X86_ASSEMBLER # define UNIV_CAN_USE_X86_ASSEMBLER
# endif # endif
/* For InnoDB rw_locks to work with atomics we need the thread_id
to be no more than machine word wide. The following enables using
atomics for InnoDB rw_locks where these conditions are met. */
# if defined(HAVE_GCC_ATOMIC_BUILTINS) && defined(UNIV_LINUX)
# define INNODB_RW_LOCKS_USE_ATOMICS
# endif
/* We only try to do explicit inlining of functions with gcc and /* We only try to do explicit inlining of functions with gcc and
Microsoft Visual C++ */ Microsoft Visual C++ */
......
...@@ -739,7 +739,7 @@ log_init(void) ...@@ -739,7 +739,7 @@ log_init(void)
ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE); ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE);
ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE); ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE);
buf = ut_malloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE); buf = mem_alloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE);
log_sys->buf = ut_align(buf, OS_FILE_LOG_BLOCK_SIZE); log_sys->buf = ut_align(buf, OS_FILE_LOG_BLOCK_SIZE);
log_sys->buf_size = LOG_BUFFER_SIZE; log_sys->buf_size = LOG_BUFFER_SIZE;
......
...@@ -591,6 +591,7 @@ not_consistent: ...@@ -591,6 +591,7 @@ not_consistent:
return(DB_SUCCESS); return(DB_SUCCESS);
} }
#ifdef UNIV_HOTBACKUP
/*********************************************************************** /***********************************************************************
Reads the checkpoint info needed in hot backup. */ Reads the checkpoint info needed in hot backup. */
UNIV_INTERN UNIV_INTERN
...@@ -661,6 +662,7 @@ recv_read_cp_info_for_backup( ...@@ -661,6 +662,7 @@ recv_read_cp_info_for_backup(
return(TRUE); return(TRUE);
} }
#endif /* UNIV_HOTBACKUP */
/********************************************************** /**********************************************************
Checks the 4-byte checksum to the trailer checksum field of a log block. Checks the 4-byte checksum to the trailer checksum field of a log block.
...@@ -698,6 +700,7 @@ log_block_checksum_is_ok_or_old_format( ...@@ -698,6 +700,7 @@ log_block_checksum_is_ok_or_old_format(
return(FALSE); return(FALSE);
} }
#ifdef UNIV_HOTBACKUP
/*********************************************************************** /***********************************************************************
Scans the log segment and n_bytes_scanned is set to the length of valid Scans the log segment and n_bytes_scanned is set to the length of valid
log scanned. */ log scanned. */
...@@ -787,6 +790,7 @@ recv_scan_log_seg_for_backup( ...@@ -787,6 +790,7 @@ recv_scan_log_seg_for_backup(
} }
} }
} }
#endif /* UNIV_HOTBACKUP */
/*********************************************************************** /***********************************************************************
Tries to parse a single log record body and also applies it to a page if Tries to parse a single log record body and also applies it to a page if
......
...@@ -478,7 +478,9 @@ mem_area_free( ...@@ -478,7 +478,9 @@ mem_area_free(
ulint n; ulint n;
if (srv_use_sys_malloc) { if (srv_use_sys_malloc) {
return(free(ptr)); free(ptr);
return;
} }
/* It may be that the area was really allocated from the OS with /* It may be that the area was really allocated from the OS with
......
...@@ -419,3 +419,6 @@ select @@innodb_file_format_check; ...@@ -419,3 +419,6 @@ select @@innodb_file_format_check;
@@innodb_file_format_check @@innodb_file_format_check
Barracuda Barracuda
drop table normal_table, zip_table; drop table normal_table, zip_table;
set global innodb_file_format=Antelope;
set global innodb_file_per_table=0;
set global innodb_file_format_check=Antelope;
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
let $per_table=`select @@innodb_file_per_table`; let $per_table=`select @@innodb_file_per_table`;
let $format=`select @@innodb_file_format`; let $format=`select @@innodb_file_format`;
let $innodb_file_format_check_orig=`select @@innodb_file_format_check`;
set global innodb_file_per_table=off; set global innodb_file_per_table=off;
set global innodb_file_format=`0`; set global innodb_file_format=`0`;
...@@ -157,7 +158,8 @@ set global innodb_file_format=`1a`; ...@@ -157,7 +158,8 @@ set global innodb_file_format=`1a`;
set global innodb_file_format=``; set global innodb_file_format=``;
#test strict mode. #test strict mode.
--enable_errors # this does not work anymore, has been removed from mysqltest
# -- enable_errors
set global innodb_file_per_table = on; set global innodb_file_per_table = on;
set global innodb_file_format = `1`; set global innodb_file_format = `1`;
...@@ -330,3 +332,11 @@ show table status; ...@@ -330,3 +332,11 @@ show table status;
select @@innodb_file_format_check; select @@innodb_file_format_check;
drop table normal_table, zip_table; drop table normal_table, zip_table;
-- disable_result_log -- disable_result_log
#
# restore environment to the state it was before this test execution
#
eval set global innodb_file_format=$format;
eval set global innodb_file_per_table=$per_table;
eval set global innodb_file_format_check=$innodb_file_format_check_orig;
--- mysql-test/t/date_formats.test.orig 2007-06-15 02:53:07.000000000 +0300
+++ mysql-test/t/date_formats.test 2008-03-19 17:25:10.000000000 +0200
@@ -7,9 +7,15 @@
--enable_warnings
--replace_result ROW <format> STATEMENT <format> MIXED <format>
-SHOW GLOBAL VARIABLES LIKE "%e_format";
+SELECT variable_name, variable_value
+FROM information_schema.global_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
--replace_result ROW <format> STATEMENT <format> MIXED <format>
-SHOW SESSION VARIABLES LIKE "%e_format";
+SELECT variable_name, variable_value
+FROM information_schema.session_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
#
# Test setting a lot of different formats to see which formats are accepted and
@@ -37,7 +43,10 @@
set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d';
--replace_result ROW <format> STATEMENT <format> MIXED <format>
-SHOW SESSION VARIABLES LIKE "%e_format";
+SELECT variable_name, variable_value
+FROM information_schema.session_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
--error 1231
SET time_format='%h:%i:%s';
--- mysql-test/r/date_formats.result.orig 2008-02-12 21:09:14.000000000 +0200
+++ mysql-test/r/date_formats.result 2008-03-19 17:26:33.000000000 +0200
@@ -1,14 +1,20 @@
drop table if exists t1;
-SHOW GLOBAL VARIABLES LIKE "%e_format";
-Variable_name Value
-date_format %d.%m.%Y
-datetime_format %Y-%m-%d %H:%i:%s
-time_format %H.%i.%s
-SHOW SESSION VARIABLES LIKE "%e_format";
-Variable_name Value
-date_format %d.%m.%Y
-datetime_format %Y-%m-%d %H:%i:%s
-time_format %H.%i.%s
+SELECT variable_name, variable_value
+FROM information_schema.global_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
+variable_name variable_value
+DATETIME_FORMAT %Y-%m-%d %H:%i:%s
+DATE_FORMAT %d.%m.%Y
+TIME_FORMAT %H.%i.%s
+SELECT variable_name, variable_value
+FROM information_schema.session_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
+variable_name variable_value
+DATETIME_FORMAT %Y-%m-%d %H:%i:%s
+DATE_FORMAT %d.%m.%Y
+TIME_FORMAT %H.%i.%s
SET time_format='%H%i%s';
SET time_format='%H:%i:%s.%f';
SET time_format='%h-%i-%s.%f%p';
@@ -26,11 +32,14 @@
set datetime_format= '%H:%i:%s.%f %m-%d-%Y';
set datetime_format= '%h:%i:%s %p %Y-%m-%d';
set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d';
-SHOW SESSION VARIABLES LIKE "%e_format";
-Variable_name Value
-date_format %m-%d-%Y
-datetime_format %h:%i:%s.%f %p %Y-%m-%d
-time_format %h:%i:%s%p
+SELECT variable_name, variable_value
+FROM information_schema.session_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
+variable_name variable_value
+DATETIME_FORMAT %h:%i:%s.%f %p %Y-%m-%d
+DATE_FORMAT %m-%d-%Y
+TIME_FORMAT %h:%i:%s%p
SET time_format='%h:%i:%s';
ERROR 42000: Variable 'time_format' can't be set to the value of '%h:%i:%s'
SET time_format='%H %i:%s';
diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema.result --- mysql-test/r/information_schema.result.orig 2009-01-31 03:38:50.000000000 +0200
--- mysql-test/r/information_schema.result.orig 2008-08-04 09:27:49.000000000 +0300 +++ mysql-test/r/information_schema.result 2009-01-31 07:51:58.000000000 +0200
+++ mysql-test/r/information_schema.result 2008-10-07 11:21:51.000000000 +0300 @@ -71,6 +71,13 @@
@@ -64,6 +64,13 @@
TRIGGERS TRIGGERS
USER_PRIVILEGES USER_PRIVILEGES
VIEWS VIEWS
...@@ -15,7 +14,7 @@ diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema ...@@ -15,7 +14,7 @@ diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema
columns_priv columns_priv
db db
event event
@@ -795,6 +802,8 @@ @@ -799,6 +806,8 @@
TABLES UPDATE_TIME datetime TABLES UPDATE_TIME datetime
TABLES CHECK_TIME datetime TABLES CHECK_TIME datetime
TRIGGERS CREATED datetime TRIGGERS CREATED datetime
...@@ -24,16 +23,16 @@ diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema ...@@ -24,16 +23,16 @@ diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema
event execute_at datetime event execute_at datetime
event last_executed datetime event last_executed datetime
event starts datetime event starts datetime
@@ -848,7 +857,7 @@ @@ -852,7 +861,7 @@
flush privileges; flush privileges;
SELECT table_schema, count(*) FROM information_schema.TABLES where table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA;
table_schema count(*) table_schema count(*)
-information_schema 28 -information_schema 28
+information_schema 35 +information_schema 35
mysql 22 mysql 22
create table t1 (i int, j int); create table t1 (i int, j int);
create trigger trg1 before insert on t1 for each row create trigger trg1 before insert on t1 for each row
@@ -1263,6 +1272,13 @@ @@ -1267,6 +1276,13 @@
TRIGGERS TRIGGER_SCHEMA TRIGGERS TRIGGER_SCHEMA
USER_PRIVILEGES GRANTEE USER_PRIVILEGES GRANTEE
VIEWS TABLE_SCHEMA VIEWS TABLE_SCHEMA
...@@ -47,7 +46,7 @@ diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema ...@@ -47,7 +46,7 @@ diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema
SELECT t.table_name, c1.column_name SELECT t.table_name, c1.column_name
FROM information_schema.tables t FROM information_schema.tables t
INNER JOIN INNER JOIN
@@ -1306,6 +1322,13 @@ @@ -1310,6 +1326,13 @@
TRIGGERS TRIGGER_SCHEMA TRIGGERS TRIGGER_SCHEMA
USER_PRIVILEGES GRANTEE USER_PRIVILEGES GRANTEE
VIEWS TABLE_SCHEMA VIEWS TABLE_SCHEMA
...@@ -58,10 +57,10 @@ diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema ...@@ -58,10 +57,10 @@ diff mysql-test/r/information_schema.result.orig mysql-test/r/information_schema
+INNODB_CMPMEM page_size +INNODB_CMPMEM page_size
+INNODB_CMP page_size +INNODB_CMP page_size
+INNODB_LOCKS lock_id +INNODB_LOCKS lock_id
SELECT MAX(table_name) FROM information_schema.tables; SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test');
MAX(table_name) MAX(table_name)
VIEWS VIEWS
@@ -1382,6 +1405,13 @@ @@ -1386,6 +1409,13 @@
FILES information_schema.FILES 1 FILES information_schema.FILES 1
GLOBAL_STATUS information_schema.GLOBAL_STATUS 1 GLOBAL_STATUS information_schema.GLOBAL_STATUS 1
GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1 GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1
......
...@@ -5,6 +5,38 @@ Select ...@@ -5,6 +5,38 @@ Select
Created 12/19/1997 Heikki Tuuri Created 12/19/1997 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "row0sel.h" #include "row0sel.h"
...@@ -1339,7 +1371,7 @@ table_loop: ...@@ -1339,7 +1371,7 @@ table_loop:
rw_lock_s_lock(&btr_search_latch); rw_lock_s_lock(&btr_search_latch);
search_latch_locked = TRUE; search_latch_locked = TRUE;
} else if (btr_search_latch.writer_is_wait_ex) { } else if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_WAIT_EX) {
/* There is an x-latch request waiting: release the /* There is an x-latch request waiting: release the
s-latch for a moment; as an s-latch here is often s-latch for a moment; as an s-latch here is often
...@@ -3364,7 +3396,7 @@ row_search_for_mysql( ...@@ -3364,7 +3396,7 @@ row_search_for_mysql(
/* PHASE 0: Release a possible s-latch we are holding on the /* PHASE 0: Release a possible s-latch we are holding on the
adaptive hash index latch if there is someone waiting behind */ adaptive hash index latch if there is someone waiting behind */
if (UNIV_UNLIKELY(btr_search_latch.writer != RW_LOCK_NOT_LOCKED) if (UNIV_UNLIKELY(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_NOT_LOCKED)
&& trx->has_search_latch) { && trx->has_search_latch) {
/* There is an x-latch request on the adaptive hash index: /* There is an x-latch request on the adaptive hash index:
......
...@@ -24,6 +24,38 @@ thread library. This might confuse NT though. ...@@ -24,6 +24,38 @@ thread library. This might confuse NT though.
Created 10/8/1995 Heikki Tuuri Created 10/8/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
/* Dummy comment */ /* Dummy comment */
#include "srv0srv.h" #include "srv0srv.h"
...@@ -1828,6 +1860,11 @@ srv_export_innodb_status(void) ...@@ -1828,6 +1860,11 @@ srv_export_innodb_status(void)
export_vars.innodb_buffer_pool_pages_misc = buf_pool->curr_size export_vars.innodb_buffer_pool_pages_misc = buf_pool->curr_size
- UT_LIST_GET_LEN(buf_pool->LRU) - UT_LIST_GET_LEN(buf_pool->LRU)
- UT_LIST_GET_LEN(buf_pool->free); - UT_LIST_GET_LEN(buf_pool->free);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
export_vars.innodb_have_atomic_builtins = 1;
#else
export_vars.innodb_have_atomic_builtins = 0;
#endif
export_vars.innodb_page_size = UNIV_PAGE_SIZE; export_vars.innodb_page_size = UNIV_PAGE_SIZE;
export_vars.innodb_log_waits = srv_log_waits; export_vars.innodb_log_waits = srv_log_waits;
export_vars.innodb_os_log_written = srv_os_log_written; export_vars.innodb_os_log_written = srv_os_log_written;
......
...@@ -5,6 +5,38 @@ Starts the InnoDB database server ...@@ -5,6 +5,38 @@ Starts the InnoDB database server
Created 2/16/1996 Heikki Tuuri Created 2/16/1996 Heikki Tuuri
*************************************************************************/ *************************************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "os0proc.h" #include "os0proc.h"
#include "sync0sync.h" #include "sync0sync.h"
...@@ -956,8 +988,7 @@ skip_size_check: ...@@ -956,8 +988,7 @@ skip_size_check:
/******************************************************************** /********************************************************************
Starts InnoDB and creates a new database if database files Starts InnoDB and creates a new database if database files
are not found and the user wants. Server parameters are are not found and the user wants. */
read from a file of name "srv_init" in the ib_home directory. */
UNIV_INTERN UNIV_INTERN
int int
innobase_start_or_create_for_mysql(void) innobase_start_or_create_for_mysql(void)
...@@ -1053,6 +1084,17 @@ innobase_start_or_create_for_mysql(void) ...@@ -1053,6 +1084,17 @@ innobase_start_or_create_for_mysql(void)
"InnoDB: The InnoDB memory heap is disabled\n"); "InnoDB: The InnoDB memory heap is disabled\n");
} }
#ifdef HAVE_GCC_ATOMIC_BUILTINS
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
fprintf(stderr,
"InnoDB: Mutex and rw_lock use GCC atomic builtins.\n");
#else
fprintf(stderr,
"InnoDB: Mutex use GCC atomic builtins.\n");
#endif
#endif
/* Since InnoDB does not currently clean up all its internal data /* Since InnoDB does not currently clean up all its internal data
structures in MySQL Embedded Server Library server_end(), we structures in MySQL Embedded Server Library server_end(), we
print an error message if someone tries to start up InnoDB a print an error message if someone tries to start up InnoDB a
......
...@@ -5,6 +5,38 @@ The wait array used in synchronization primitives ...@@ -5,6 +5,38 @@ The wait array used in synchronization primitives
Created 9/5/1995 Heikki Tuuri Created 9/5/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "sync0arr.h" #include "sync0arr.h"
#ifdef UNIV_NONINL #ifdef UNIV_NONINL
...@@ -295,25 +327,21 @@ sync_array_validate( ...@@ -295,25 +327,21 @@ sync_array_validate(
} }
/*********************************************************************** /***********************************************************************
Puts the cell event in reset state. */ Returns the event that the thread owning the cell waits for. */
static static
ib_int64_t os_event_t
sync_cell_event_reset( sync_cell_get_event(
/*==================*/ /*================*/
/* out: value of signal_count sync_cell_t* cell) /* in: non-empty sync array cell */
at the time of reset. */
ulint type, /* in: lock type mutex/rw_lock */
void* object) /* in: the rw_lock/mutex object */
{ {
ulint type = cell->request_type;
if (type == SYNC_MUTEX) { if (type == SYNC_MUTEX) {
return(os_event_reset(((mutex_t *) object)->event)); return(((mutex_t *) cell->wait_object)->event);
#ifdef __WIN__
} else if (type == RW_LOCK_WAIT_EX) { } else if (type == RW_LOCK_WAIT_EX) {
return(os_event_reset( return(((rw_lock_t *) cell->wait_object)->wait_ex_event);
((rw_lock_t *) object)->wait_ex_event)); } else { /* RW_LOCK_SHARED and RW_LOCK_EX wait on the same event */
#endif return(((rw_lock_t *) cell->wait_object)->event);
} else {
return(os_event_reset(((rw_lock_t *) object)->event));
} }
} }
...@@ -332,6 +360,7 @@ sync_array_reserve_cell( ...@@ -332,6 +360,7 @@ sync_array_reserve_cell(
ulint* index) /* out: index of the reserved cell */ ulint* index) /* out: index of the reserved cell */
{ {
sync_cell_t* cell; sync_cell_t* cell;
os_event_t event;
ulint i; ulint i;
ut_a(object); ut_a(object);
...@@ -370,8 +399,8 @@ sync_array_reserve_cell( ...@@ -370,8 +399,8 @@ sync_array_reserve_cell(
/* Make sure the event is reset and also store /* Make sure the event is reset and also store
the value of signal_count at which the event the value of signal_count at which the event
was reset. */ was reset. */
cell->signal_count = sync_cell_event_reset(type, event = sync_cell_get_event(cell);
object); cell->signal_count = os_event_reset(event);
cell->reservation_time = time(NULL); cell->reservation_time = time(NULL);
...@@ -411,19 +440,7 @@ sync_array_wait_event( ...@@ -411,19 +440,7 @@ sync_array_wait_event(
ut_a(!cell->waiting); ut_a(!cell->waiting);
ut_ad(os_thread_get_curr_id() == cell->thread); ut_ad(os_thread_get_curr_id() == cell->thread);
if (cell->request_type == SYNC_MUTEX) { event = sync_cell_get_event(cell);
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 {
event = ((rw_lock_t*) cell->wait_object)->event;
}
cell->waiting = TRUE; cell->waiting = TRUE;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
...@@ -462,6 +479,7 @@ sync_array_cell_print( ...@@ -462,6 +479,7 @@ sync_array_cell_print(
mutex_t* mutex; mutex_t* mutex;
rw_lock_t* rwlock; rw_lock_t* rwlock;
ulint type; ulint type;
ulint writer;
type = cell->request_type; type = cell->request_type;
...@@ -491,9 +509,7 @@ sync_array_cell_print( ...@@ -491,9 +509,7 @@ sync_array_cell_print(
(ulong) mutex->waiters); (ulong) mutex->waiters);
} else if (type == RW_LOCK_EX } else if (type == RW_LOCK_EX
#ifdef __WIN__
|| type == RW_LOCK_WAIT_EX || type == RW_LOCK_WAIT_EX
#endif
|| type == RW_LOCK_SHARED) { || type == RW_LOCK_SHARED) {
fputs(type == RW_LOCK_EX ? "X-lock on" : "S-lock on", file); fputs(type == RW_LOCK_EX ? "X-lock on" : "S-lock on", file);
...@@ -504,22 +520,25 @@ sync_array_cell_print( ...@@ -504,22 +520,25 @@ sync_array_cell_print(
" RW-latch at %p created in file %s line %lu\n", " RW-latch at %p created in file %s line %lu\n",
(void*) rwlock, rwlock->cfile_name, (void*) rwlock, rwlock->cfile_name,
(ulong) rwlock->cline); (ulong) rwlock->cline);
if (rwlock->writer != RW_LOCK_NOT_LOCKED) { writer = rw_lock_get_writer(rwlock);
if (writer != RW_LOCK_NOT_LOCKED) {
fprintf(file, fprintf(file,
"a writer (thread id %lu) has" "a writer (thread id %lu) has"
" reserved it in mode %s", " reserved it in mode %s",
(ulong) os_thread_pf(rwlock->writer_thread), (ulong) os_thread_pf(rwlock->writer_thread),
rwlock->writer == RW_LOCK_EX writer == RW_LOCK_EX
? " exclusive\n" ? " exclusive\n"
: " wait exclusive\n"); : " wait exclusive\n");
} }
fprintf(file, fprintf(file,
"number of readers %lu, waiters flag %lu\n" "number of readers %lu, waiters flag %lu, "
"lock_word: %lx\n"
"Last time read locked in file %s line %lu\n" "Last time read locked in file %s line %lu\n"
"Last time write locked in file %s line %lu\n", "Last time write locked in file %s line %lu\n",
(ulong) rwlock->reader_count, (ulong) rw_lock_get_reader_count(rwlock),
(ulong) rwlock->waiters, (ulong) rwlock->waiters,
rwlock->lock_word,
rwlock->last_s_file_name, rwlock->last_s_file_name,
(ulong) rwlock->last_s_line, (ulong) rwlock->last_s_line,
rwlock->last_x_file_name, rwlock->last_x_file_name,
...@@ -778,28 +797,30 @@ sync_arr_cell_can_wake_up( ...@@ -778,28 +797,30 @@ sync_arr_cell_can_wake_up(
return(TRUE); return(TRUE);
} }
} else if (cell->request_type == RW_LOCK_EX } else if (cell->request_type == RW_LOCK_EX) {
|| cell->request_type == RW_LOCK_WAIT_EX) {
lock = cell->wait_object; lock = cell->wait_object;
if (rw_lock_get_reader_count(lock) == 0 if (lock->lock_word > 0) {
&& rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { /* Either unlocked or only read locked. */
return(TRUE); return(TRUE);
} }
if (rw_lock_get_reader_count(lock) == 0 } else if (cell->request_type == RW_LOCK_WAIT_EX) {
&& rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX
&& os_thread_eq(lock->writer_thread, cell->thread)) { lock = cell->wait_object;
/* lock_word == 0 means all readers have left */
if (lock->lock_word == 0) {
return(TRUE); return(TRUE);
} }
} else if (cell->request_type == RW_LOCK_SHARED) { } else if (cell->request_type == RW_LOCK_SHARED) {
lock = cell->wait_object; lock = cell->wait_object;
if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { /* lock_word > 0 means no writer or reserved writer */
if (lock->lock_word > 0) {
return(TRUE); return(TRUE);
} }
...@@ -844,11 +865,15 @@ sync_array_object_signalled( ...@@ -844,11 +865,15 @@ sync_array_object_signalled(
/*========================*/ /*========================*/
sync_array_t* arr) /* in: wait array */ sync_array_t* arr) /* in: wait array */
{ {
#ifdef HAVE_GCC_ATOMIC_BUILTINS
os_atomic_increment((lint*) &arr->sg_count, 1);
#else
sync_array_enter(arr); sync_array_enter(arr);
arr->sg_count++; arr->sg_count++;
sync_array_exit(arr); sync_array_exit(arr);
#endif
} }
/************************************************************************** /**************************************************************************
...@@ -868,6 +893,7 @@ sync_arr_wake_threads_if_sema_free(void) ...@@ -868,6 +893,7 @@ sync_arr_wake_threads_if_sema_free(void)
sync_cell_t* cell; sync_cell_t* cell;
ulint count; ulint count;
ulint i; ulint i;
os_event_t event;
sync_array_enter(arr); sync_array_enter(arr);
...@@ -877,36 +903,20 @@ sync_arr_wake_threads_if_sema_free(void) ...@@ -877,36 +903,20 @@ sync_arr_wake_threads_if_sema_free(void)
while (count < arr->n_reserved) { while (count < arr->n_reserved) {
cell = sync_array_get_nth_cell(arr, i); cell = sync_array_get_nth_cell(arr, i);
i++;
if (cell->wait_object != NULL) { if (cell->wait_object == NULL) {
continue;
}
count++; count++;
if (sync_arr_cell_can_wake_up(cell)) { if (sync_arr_cell_can_wake_up(cell)) {
if (cell->request_type == SYNC_MUTEX) { event = sync_cell_get_event(cell);
mutex_t* mutex;
mutex = cell->wait_object; os_event_set(event);
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 {
rw_lock_t* lock;
lock = cell->wait_object;
os_event_set(lock->event);
}
}
} }
i++;
} }
sync_array_exit(arr); sync_array_exit(arr);
...@@ -1026,4 +1036,3 @@ sync_array_print_info( ...@@ -1026,4 +1036,3 @@ sync_array_print_info(
sync_array_exit(arr); sync_array_exit(arr);
} }
...@@ -5,6 +5,38 @@ The read-write lock (for thread synchronization) ...@@ -5,6 +5,38 @@ The read-write lock (for thread synchronization)
Created 9/11/1995 Heikki Tuuri Created 9/11/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "sync0rw.h" #include "sync0rw.h"
#ifdef UNIV_NONINL #ifdef UNIV_NONINL
...@@ -15,35 +47,125 @@ Created 9/11/1995 Heikki Tuuri ...@@ -15,35 +47,125 @@ Created 9/11/1995 Heikki Tuuri
#include "mem0mem.h" #include "mem0mem.h"
#include "srv0srv.h" #include "srv0srv.h"
/* number of system calls made during shared latching */ /*
UNIV_INTERN ulint rw_s_system_call_count = 0; IMPLEMENTATION OF THE RW_LOCK
=============================
The status of a rw_lock is held in lock_word. The initial value of lock_word is
X_LOCK_DECR. lock_word is decremented by 1 for each s-lock and by X_LOCK_DECR
for each x-lock. This describes the lock state for each value of lock_word:
lock_word == X_LOCK_DECR: Unlocked.
0 < lock_word < X_LOCK_DECR: Read locked, no waiting writers.
(X_LOCK_DECR - lock_word) is the
number of readers that hold the lock.
lock_word == 0: Write locked
-X_LOCK_DECR < lock_word < 0: Read locked, with a waiting writer.
(-lock_word) is the number of readers
that hold the lock.
lock_word <= -X_LOCK_DECR: Recursively write locked. lock_word has been
decremented by X_LOCK_DECR once for each lock,
so the number of locks is:
((-lock_word) / X_LOCK_DECR) + 1
When lock_word <= -X_LOCK_DECR, we also know that lock_word % X_LOCK_DECR == 0:
other values of lock_word are invalid.
The lock_word is always read and updated atomically and consistently, so that
it always represents the state of the lock, and the state of the lock changes
with a single atomic operation. This lock_word holds all of the information
that a thread needs in order to determine if it is eligible to gain the lock
or if it must spin or sleep. The one exception to this is that writer_thread
must be verified before recursive write locks: to solve this scenario, we make
writer_thread readable by all threads, but only writeable by the x-lock holder.
The other members of the lock obey the following rules to remain consistent:
recursive: This and the writer_thread field together control the
behaviour of recursive x-locking.
lock->recursive must be FALSE in following states:
1) The writer_thread contains garbage i.e.: the
lock has just been initialized.
2) The lock is not x-held and there is no
x-waiter waiting on WAIT_EX event.
3) The lock is x-held or there is an x-waiter
waiting on WAIT_EX event but the 'pass' value
is non-zero.
lock->recursive is TRUE iff:
1) The lock is x-held or there is an x-waiter
waiting on WAIT_EX event and the 'pass' value
is zero.
This flag must be set after the writer_thread field
has been updated with a memory ordering barrier.
It is unset before the lock_word has been incremented.
writer_thread: Is used only in recursive x-locking. Can only be safely
read iff lock->recursive flag is TRUE.
This field is uninitialized at lock creation time and
is updated atomically when x-lock is acquired or when
move_ownership is called. A thread is only allowed to
set the value of this field to it's thread_id i.e.: a
thread cannot set writer_thread to some other thread's
id.
waiters: May be set to 1 anytime, but to avoid unnecessary wake-up
signals, it should only be set to 1 when there are threads
waiting on event. Must be 1 when a writer starts waiting to
ensure the current x-locking thread sends a wake-up signal
during unlock. May only be reset to 0 immediately before a
a wake-up signal is sent to event. On most platforms, a
memory barrier is required after waiters is set, and before
verifying lock_word is still held, to ensure some unlocker
really does see the flags new value.
event: Threads wait on event for read or writer lock when another
thread has an x-lock or an x-lock reservation (wait_ex). A
thread may only wait on event after performing the following
actions in order:
(1) Record the counter value of event (with os_event_reset).
(2) Set waiters to 1.
(3) Verify lock_word <= 0.
(1) must come before (2) to ensure signal is not missed.
(2) must come before (3) to ensure a signal is sent.
These restrictions force the above ordering.
Immediately before sending the wake-up signal, we should:
(1) Verify lock_word == X_LOCK_DECR (unlocked)
(2) Reset waiters to 0.
wait_ex_event: A thread may only wait on the wait_ex_event after it has
performed the following actions in order:
(1) Decrement lock_word by X_LOCK_DECR.
(2) Record counter value of wait_ex_event (os_event_reset,
called from sync_array_reserve_cell).
(3) Verify that lock_word < 0.
(1) must come first to ensures no other threads become reader
or next writer, and notifies unlocker that signal must be sent.
(2) must come before (3) to ensure the signal is not missed.
These restrictions force the above ordering.
Immediately before sending the wake-up signal, we should:
Verify lock_word == 0 (waiting thread holds x_lock)
*/
/* number of spin waits on rw-latches, /* number of spin waits on rw-latches,
resulted during shared (read) locks */ resulted during shared (read) locks */
UNIV_INTERN ulint rw_s_spin_wait_count = 0; UNIV_INTERN ib_int64_t rw_s_spin_wait_count = 0;
UNIV_INTERN ib_int64_t rw_s_spin_round_count = 0;
/* number of OS waits on rw-latches, /* number of OS waits on rw-latches,
resulted during shared (read) locks */ resulted during shared (read) locks */
UNIV_INTERN ulint rw_s_os_wait_count = 0; UNIV_INTERN ib_int64_t rw_s_os_wait_count = 0;
/* number of unlocks (that unlock shared locks), /* number of unlocks (that unlock shared locks),
set only when UNIV_SYNC_PERF_STAT is defined */ set only when UNIV_SYNC_PERF_STAT is defined */
UNIV_INTERN ulint rw_s_exit_count = 0; UNIV_INTERN ib_int64_t rw_s_exit_count = 0;
/* number of system calls made during exclusive latching */
UNIV_INTERN ulint rw_x_system_call_count = 0;
/* number of spin waits on rw-latches, /* number of spin waits on rw-latches,
resulted during exclusive (write) locks */ resulted during exclusive (write) locks */
UNIV_INTERN ulint rw_x_spin_wait_count = 0; UNIV_INTERN ib_int64_t rw_x_spin_wait_count = 0;
UNIV_INTERN ib_int64_t rw_x_spin_round_count = 0;
/* number of OS waits on rw-latches, /* number of OS waits on rw-latches,
resulted during exclusive (write) locks */ resulted during exclusive (write) locks */
UNIV_INTERN ulint rw_x_os_wait_count = 0; UNIV_INTERN ib_int64_t rw_x_os_wait_count = 0;
/* number of unlocks (that unlock exclusive locks), /* number of unlocks (that unlock exclusive locks),
set only when UNIV_SYNC_PERF_STAT is defined */ set only when UNIV_SYNC_PERF_STAT is defined */
UNIV_INTERN ulint rw_x_exit_count = 0; UNIV_INTERN ib_int64_t rw_x_exit_count = 0;
/* The global list of rw-locks */ /* The global list of rw-locks */
UNIV_INTERN rw_lock_list_t rw_lock_list; UNIV_INTERN rw_lock_list_t rw_lock_list;
...@@ -114,11 +236,12 @@ rw_lock_create_func( ...@@ -114,11 +236,12 @@ rw_lock_create_func(
const char* cmutex_name, /* in: mutex name */ const char* cmutex_name, /* in: mutex name */
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
const char* cfile_name, /* in: file name where created */ const char* cfile_name, /* in: file name where created */
ulint cline) /* in: file line where created */ ulint cline) /* in: file line where created */
{ {
/* If this is the very first time a synchronization object is /* If this is the very first time a synchronization object is
created, then the following call initializes the sync system. */ created, then the following call initializes the sync system. */
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK); mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
lock->mutex.cfile_name = cfile_name; lock->mutex.cfile_name = cfile_name;
...@@ -129,12 +252,19 @@ rw_lock_create_func( ...@@ -129,12 +252,19 @@ rw_lock_create_func(
lock->mutex.mutex_type = 1; lock->mutex.mutex_type = 1;
#endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */ #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
rw_lock_set_waiters(lock, 0); #else /* INNODB_RW_LOCKS_USE_ATOMICS */
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); #ifdef UNIV_DEBUG
lock->writer_count = 0; UT_NOT_USED(cmutex_name);
rw_lock_set_reader_count(lock, 0); #endif
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->lock_word = X_LOCK_DECR;
lock->waiters = 0;
lock->writer_is_wait_ex = FALSE; /* We set this value to signify that lock->writer_thread
contains garbage at initialization and cannot be used for
recursive x-locking. */
lock->recursive = FALSE;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
UT_LIST_INIT(lock->debug_list); UT_LIST_INIT(lock->debug_list);
...@@ -147,15 +277,13 @@ rw_lock_create_func( ...@@ -147,15 +277,13 @@ rw_lock_create_func(
lock->cfile_name = cfile_name; lock->cfile_name = cfile_name;
lock->cline = (unsigned int) cline; lock->cline = (unsigned int) cline;
lock->count_os_wait = 0;
lock->last_s_file_name = "not yet reserved"; lock->last_s_file_name = "not yet reserved";
lock->last_x_file_name = "not yet reserved"; lock->last_x_file_name = "not yet reserved";
lock->last_s_line = 0; lock->last_s_line = 0;
lock->last_x_line = 0; lock->last_x_line = 0;
lock->event = os_event_create(NULL); lock->event = os_event_create(NULL);
#ifdef __WIN__
lock->wait_ex_event = os_event_create(NULL); lock->wait_ex_event = os_event_create(NULL);
#endif
mutex_enter(&rw_lock_list_mutex); mutex_enter(&rw_lock_list_mutex);
...@@ -180,20 +308,18 @@ rw_lock_free( ...@@ -180,20 +308,18 @@ rw_lock_free(
rw_lock_t* lock) /* in: rw-lock */ rw_lock_t* lock) /* in: rw-lock */
{ {
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); ut_a(lock->lock_word == X_LOCK_DECR);
ut_a(rw_lock_get_waiters(lock) == 0);
ut_a(rw_lock_get_reader_count(lock) == 0);
lock->magic_n = 0; lock->magic_n = 0;
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
mutex_free(rw_lock_get_mutex(lock)); mutex_free(rw_lock_get_mutex(lock));
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
mutex_enter(&rw_lock_list_mutex); mutex_enter(&rw_lock_list_mutex);
os_event_free(lock->event); os_event_free(lock->event);
#ifdef __WIN__
os_event_free(lock->wait_ex_event); os_event_free(lock->wait_ex_event);
#endif
if (UT_LIST_GET_PREV(list, lock)) { if (UT_LIST_GET_PREV(list, lock)) {
ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N); ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
...@@ -219,19 +345,12 @@ rw_lock_validate( ...@@ -219,19 +345,12 @@ rw_lock_validate(
{ {
ut_a(lock); ut_a(lock);
mutex_enter(rw_lock_get_mutex(lock)); ulint waiters = rw_lock_get_waiters(lock);
lint lock_word = lock->lock_word;
ut_a(lock->magic_n == RW_LOCK_MAGIC_N); ut_a(lock->magic_n == RW_LOCK_MAGIC_N);
ut_a((rw_lock_get_reader_count(lock) == 0) ut_a(waiters == 0 || waiters == 1);
|| (rw_lock_get_writer(lock) != RW_LOCK_EX)); ut_a(lock_word > -X_LOCK_DECR ||(-lock_word) % X_LOCK_DECR == 0);
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((lock->writer != RW_LOCK_EX) || (lock->writer_count > 0));
mutex_exit(rw_lock_get_mutex(lock));
return(TRUE); return(TRUE);
} }
...@@ -253,18 +372,15 @@ rw_lock_s_lock_spin( ...@@ -253,18 +372,15 @@ rw_lock_s_lock_spin(
ulint line) /* in: line where requested */ ulint line) /* in: line where requested */
{ {
ulint index; /* index of the reserved wait cell */ ulint index; /* index of the reserved wait cell */
ulint i; /* spin round count */ ulint i = 0; /* spin round count */
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
rw_s_spin_wait_count++; /* Count calls to this function */
lock_loop: lock_loop:
rw_s_spin_wait_count++;
/* Spin waiting for the writer field to become free */ /* Spin waiting for the writer field to become free */
i = 0; while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) {
while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
&& i < SYNC_SPIN_ROUNDS) {
if (srv_spin_wait_delay) { if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
} }
...@@ -285,28 +401,32 @@ lock_loop: ...@@ -285,28 +401,32 @@ lock_loop:
lock->cfile_name, (ulong) lock->cline, (ulong) i); lock->cfile_name, (ulong) lock->cline, (ulong) i);
} }
mutex_enter(rw_lock_get_mutex(lock));
/* We try once again to obtain the lock */ /* We try once again to obtain the lock */
if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) { if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
mutex_exit(rw_lock_get_mutex(lock)); rw_s_spin_round_count += i;
return; /* Success */ return; /* Success */
} else { } else {
/* If we get here, locking did not succeed, we may
suspend the thread to wait in the wait array */
rw_s_system_call_count++; if (i < SYNC_SPIN_ROUNDS) {
goto lock_loop;
}
rw_s_spin_round_count += i;
sync_array_reserve_cell(sync_primary_wait_array, sync_array_reserve_cell(sync_primary_wait_array,
lock, RW_LOCK_SHARED, lock, RW_LOCK_SHARED,
file_name, line, file_name, line,
&index); &index);
rw_lock_set_waiters(lock, 1); /* Set waiters before checking lock_word to ensure wake-up
signal is sent. This may lead to some unnecessary signals. */
rw_lock_set_waiter_flag(lock);
mutex_exit(rw_lock_get_mutex(lock)); if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
sync_array_free_cell(sync_primary_wait_array, index);
return; /* Success */
}
if (srv_print_latch_waits) { if (srv_print_latch_waits) {
fprintf(stderr, fprintf(stderr,
...@@ -317,11 +437,13 @@ lock_loop: ...@@ -317,11 +437,13 @@ lock_loop:
(ulong) lock->cline); (ulong) lock->cline);
} }
rw_s_system_call_count++; /* these stats may not be accurate */
lock->count_os_wait++;
rw_s_os_wait_count++; rw_s_os_wait_count++;
sync_array_wait_event(sync_primary_wait_array, index); sync_array_wait_event(sync_primary_wait_array, index);
i = 0;
goto lock_loop; goto lock_loop;
} }
} }
...@@ -343,113 +465,130 @@ rw_lock_x_lock_move_ownership( ...@@ -343,113 +465,130 @@ rw_lock_x_lock_move_ownership(
{ {
ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX)); ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));
mutex_enter(&(lock->mutex)); rw_lock_set_writer_id_and_recursion_flag(lock, TRUE);
lock->writer_thread = os_thread_get_curr_id();
lock->pass = 0;
mutex_exit(&(lock->mutex));
} }
/********************************************************************** /**********************************************************************
Low-level function for acquiring an exclusive lock. */ Function for the next writer to call. Waits for readers to exit.
The caller must have already decremented lock_word by X_LOCK_DECR.*/
UNIV_INLINE UNIV_INLINE
ulint void
rw_lock_x_lock_low( rw_lock_x_lock_wait(
/*===============*/ /*================*/
/* out: RW_LOCK_NOT_LOCKED if did
not succeed, RW_LOCK_EX if success,
RW_LOCK_WAIT_EX, if got wait reservation */
rw_lock_t* lock, /* in: pointer to rw-lock */ rw_lock_t* lock, /* in: pointer to rw-lock */
#ifdef UNIV_SYNC_DEBUG
ulint pass, /* in: pass value; != 0, if the lock will ulint pass, /* in: pass value; != 0, if the lock will
be passed to another thread to unlock */ be passed to another thread to unlock */
#endif
const char* file_name,/* in: file name where lock requested */ const char* file_name,/* in: file name where lock requested */
ulint line) /* in: line where requested */ ulint line) /* in: line where requested */
{ {
ut_ad(mutex_own(rw_lock_get_mutex(lock))); ulint index;
ulint i = 0;
if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { ut_ad(lock->lock_word <= 0);
if (rw_lock_get_reader_count(lock) == 0) { while (lock->lock_word < 0) {
if (srv_spin_wait_delay) {
rw_lock_set_writer(lock, RW_LOCK_EX); ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
lock->writer_thread = os_thread_get_curr_id(); }
lock->writer_count++; if(i < SYNC_SPIN_ROUNDS) {
lock->pass = pass; i++;
continue;
}
#ifdef UNIV_SYNC_DEBUG /* If there is still a reader, then go to sleep.*/
rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, rw_x_spin_round_count += i;
file_name, line); i = 0;
#endif sync_array_reserve_cell(sync_primary_wait_array,
lock->last_x_file_name = file_name; lock,
lock->last_x_line = (unsigned int) line; RW_LOCK_WAIT_EX,
file_name, line,
&index);
/* Check lock_word to ensure wake-up isn't missed.*/
if(lock->lock_word < 0) {
/* Locking succeeded, we may return */ /* these stats may not be accurate */
return(RW_LOCK_EX); lock->count_os_wait++;
} else { rw_x_os_wait_count++;
/* There are readers, we have to wait */
rw_lock_set_writer(lock, RW_LOCK_WAIT_EX);
lock->writer_thread = os_thread_get_curr_id();
lock->pass = pass;
lock->writer_is_wait_ex = TRUE;
/* Add debug info as it is needed to detect possible
deadlock. We must add info for WAIT_EX thread for
deadlock detection to work properly. */
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX, rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
file_name, line); file_name, line);
#endif #endif
return(RW_LOCK_WAIT_EX); sync_array_wait_event(sync_primary_wait_array,
} index);
} else if ((rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX)
&& os_thread_eq(lock->writer_thread,
os_thread_get_curr_id())) {
if (rw_lock_get_reader_count(lock) == 0) {
rw_lock_set_writer(lock, RW_LOCK_EX);
lock->writer_count++;
lock->pass = pass;
lock->writer_is_wait_ex = FALSE;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX); rw_lock_remove_debug_info(lock, pass,
rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, RW_LOCK_WAIT_EX);
file_name, line);
#endif #endif
/* It is possible to wake when lock_word < 0.
lock->last_x_file_name = file_name; We must pass the while-loop check to proceed.*/
lock->last_x_line = (unsigned int) line; } else {
sync_array_free_cell(sync_primary_wait_array,
/* Locking succeeded, we may return */ index);
return(RW_LOCK_EX);
} }
}
rw_x_spin_round_count += i;
}
/**********************************************************************
Low-level function for acquiring an exclusive lock. */
UNIV_INLINE
ibool
rw_lock_x_lock_low(
/*===============*/
/* out: RW_LOCK_NOT_LOCKED if did
not succeed, RW_LOCK_EX if success. */
rw_lock_t* lock, /* in: pointer to rw-lock */
ulint pass, /* in: pass value; != 0, if the lock will
be passed to another thread to unlock */
const char* file_name,/* in: file name where lock requested */
ulint line) /* in: line where requested */
{
os_thread_id_t curr_thread = os_thread_get_curr_id();
return(RW_LOCK_WAIT_EX); if (rw_lock_lock_word_decr(lock, X_LOCK_DECR)) {
} else if ((rw_lock_get_writer(lock) == RW_LOCK_EX) /* lock->recursive also tells us if the writer_thread
&& os_thread_eq(lock->writer_thread, field is stale or active. As we are going to write
os_thread_get_curr_id()) our own thread id in that field it must be that the
&& (lock->pass == 0) current writer_thread value is not active. */
&& (pass == 0)) { ut_a(!lock->recursive);
lock->writer_count++; /* Decrement occurred: we are writer or next-writer. */
rw_lock_set_writer_id_and_recursion_flag(lock,
pass ? FALSE : TRUE);
rw_lock_x_lock_wait(lock,
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name, pass,
line);
#endif #endif
file_name, line);
lock->last_x_file_name = file_name; } else {
lock->last_x_line = (unsigned int) line; /* Decrement failed: relock or failed lock */
if (!pass && lock->recursive &&
/* Locking succeeded, we may return */ os_thread_eq(lock->writer_thread, curr_thread)) {
return(RW_LOCK_EX); /* Relock */
lock->lock_word -= X_LOCK_DECR;
} else {
/* Another thread locked before us */
return(FALSE);
}
} }
#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 = (unsigned int) line;
/* Locking did not succeed */ return(TRUE);
return(RW_LOCK_NOT_LOCKED);
} }
/********************************************************************** /**********************************************************************
...@@ -472,47 +611,30 @@ rw_lock_x_lock_func( ...@@ -472,47 +611,30 @@ rw_lock_x_lock_func(
ulint line) /* in: line where requested */ ulint line) /* in: line where requested */
{ {
ulint index; /* index of the reserved wait cell */ ulint index; /* index of the reserved wait cell */
ulint state; /* lock state acquired */
ulint i; /* spin round count */ ulint i; /* spin round count */
ibool spinning = FALSE;
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
lock_loop: i = 0;
/* Acquire the mutex protecting the rw-lock fields */
mutex_enter_fast(&(lock->mutex));
state = rw_lock_x_lock_low(lock, pass, file_name, line);
mutex_exit(&(lock->mutex)); lock_loop:
if (state == RW_LOCK_EX) { if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
rw_x_spin_round_count += i;
return; /* Locking succeeded */ return; /* Locking succeeded */
} else if (state == RW_LOCK_NOT_LOCKED) { } else {
/* 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) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0,
srv_spin_wait_delay));
}
i++; if (!spinning) {
} spinning = TRUE;
if (i == SYNC_SPIN_ROUNDS) { rw_x_spin_wait_count++;
os_thread_yield();
} }
} else if (state == RW_LOCK_WAIT_EX) {
/* Spin waiting for the reader count field to become zero */ /* Spin waiting for the lock_word to become free */
i = 0; while (i < SYNC_SPIN_ROUNDS
&& lock->lock_word <= 0) {
while (rw_lock_get_reader_count(lock) != 0
&& i < SYNC_SPIN_ROUNDS) {
if (srv_spin_wait_delay) { if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0, ut_delay(ut_rnd_interval(0,
srv_spin_wait_delay)); srv_spin_wait_delay));
...@@ -522,12 +644,13 @@ lock_loop: ...@@ -522,12 +644,13 @@ lock_loop:
} }
if (i == SYNC_SPIN_ROUNDS) { if (i == SYNC_SPIN_ROUNDS) {
os_thread_yield(); os_thread_yield();
} else {
goto lock_loop;
} }
} else {
i = 0; /* Eliminate a compiler warning */
ut_error;
} }
rw_x_spin_round_count += i;
if (srv_print_latch_waits) { if (srv_print_latch_waits) {
fprintf(stderr, fprintf(stderr,
"Thread %lu spin wait rw-x-lock at %p" "Thread %lu spin wait rw-x-lock at %p"
...@@ -536,39 +659,20 @@ lock_loop: ...@@ -536,39 +659,20 @@ lock_loop:
lock->cfile_name, (ulong) lock->cline, (ulong) i); lock->cfile_name, (ulong) lock->cline, (ulong) i);
} }
rw_x_spin_wait_count++;
/* We try once again to obtain the lock. Acquire the mutex protecting
the rw-lock fields */
mutex_enter(rw_lock_get_mutex(lock));
state = rw_lock_x_lock_low(lock, pass, file_name, line);
if (state == RW_LOCK_EX) {
mutex_exit(rw_lock_get_mutex(lock));
return; /* Locking succeeded */
}
rw_x_system_call_count++;
sync_array_reserve_cell(sync_primary_wait_array, sync_array_reserve_cell(sync_primary_wait_array,
lock, 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, RW_LOCK_EX,
file_name, line, file_name, line,
&index); &index);
rw_lock_set_waiters(lock, 1); /* Waiters must be set before checking lock_word, to ensure signal
is sent. This could lead to a few unnecessary wake-up signals. */
rw_lock_set_waiter_flag(lock);
mutex_exit(rw_lock_get_mutex(lock)); if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
sync_array_free_cell(sync_primary_wait_array, index);
return; /* Locking succeeded */
}
if (srv_print_latch_waits) { if (srv_print_latch_waits) {
fprintf(stderr, fprintf(stderr,
...@@ -578,11 +682,13 @@ lock_loop: ...@@ -578,11 +682,13 @@ lock_loop:
lock->cfile_name, (ulong) lock->cline); lock->cfile_name, (ulong) lock->cline);
} }
rw_x_system_call_count++; /* these stats may not be accurate */
lock->count_os_wait++;
rw_x_os_wait_count++; rw_x_os_wait_count++;
sync_array_wait_event(sync_primary_wait_array, index); sync_array_wait_event(sync_primary_wait_array, index);
i = 0;
goto lock_loop; goto lock_loop;
} }
...@@ -730,7 +836,7 @@ rw_lock_own( ...@@ -730,7 +836,7 @@ rw_lock_own(
ut_ad(lock); ut_ad(lock);
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
mutex_enter(&(lock->mutex)); rw_lock_debug_mutex_enter();
info = UT_LIST_GET_FIRST(lock->debug_list); info = UT_LIST_GET_FIRST(lock->debug_list);
...@@ -740,7 +846,7 @@ rw_lock_own( ...@@ -740,7 +846,7 @@ rw_lock_own(
&& (info->pass == 0) && (info->pass == 0)
&& (info->lock_type == lock_type)) { && (info->lock_type == lock_type)) {
mutex_exit(&(lock->mutex)); rw_lock_debug_mutex_exit();
/* Found! */ /* Found! */
return(TRUE); return(TRUE);
...@@ -748,7 +854,7 @@ rw_lock_own( ...@@ -748,7 +854,7 @@ rw_lock_own(
info = UT_LIST_GET_NEXT(list, info); info = UT_LIST_GET_NEXT(list, info);
} }
mutex_exit(&(lock->mutex)); rw_lock_debug_mutex_exit();
return(FALSE); return(FALSE);
} }
...@@ -770,22 +876,18 @@ rw_lock_is_locked( ...@@ -770,22 +876,18 @@ rw_lock_is_locked(
ut_ad(lock); ut_ad(lock);
ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_validate(lock));
mutex_enter(&(lock->mutex));
if (lock_type == RW_LOCK_SHARED) { if (lock_type == RW_LOCK_SHARED) {
if (lock->reader_count > 0) { if (rw_lock_get_reader_count(lock) > 0) {
ret = TRUE; ret = TRUE;
} }
} else if (lock_type == RW_LOCK_EX) { } else if (lock_type == RW_LOCK_EX) {
if (lock->writer == RW_LOCK_EX) { if (rw_lock_get_writer(lock) == RW_LOCK_EX) {
ret = TRUE; ret = TRUE;
} }
} else { } else {
ut_error; ut_error;
} }
mutex_exit(&(lock->mutex));
return(ret); return(ret);
} }
...@@ -814,11 +916,10 @@ rw_lock_list_print_info( ...@@ -814,11 +916,10 @@ rw_lock_list_print_info(
count++; count++;
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
mutex_enter(&(lock->mutex)); mutex_enter(&(lock->mutex));
#endif
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) if (lock->lock_word != X_LOCK_DECR) {
|| (rw_lock_get_reader_count(lock) != 0)
|| (rw_lock_get_waiters(lock) != 0)) {
fprintf(file, "RW-LOCK: %p ", (void*) lock); fprintf(file, "RW-LOCK: %p ", (void*) lock);
...@@ -834,8 +935,10 @@ rw_lock_list_print_info( ...@@ -834,8 +935,10 @@ rw_lock_list_print_info(
info = UT_LIST_GET_NEXT(list, info); info = UT_LIST_GET_NEXT(list, info);
} }
} }
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
mutex_exit(&(lock->mutex)); mutex_exit(&(lock->mutex));
#endif
lock = UT_LIST_GET_NEXT(list, lock); lock = UT_LIST_GET_NEXT(list, lock);
} }
...@@ -858,9 +961,10 @@ rw_lock_print( ...@@ -858,9 +961,10 @@ rw_lock_print(
"RW-LATCH INFO\n" "RW-LATCH INFO\n"
"RW-LATCH: %p ", (void*) lock); "RW-LATCH: %p ", (void*) lock);
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) #ifndef INNODB_RW_LOCKS_USE_ATOMICS
|| (rw_lock_get_reader_count(lock) != 0) mutex_enter(&(lock->mutex));
|| (rw_lock_get_waiters(lock) != 0)) { #endif
if (lock->lock_word != X_LOCK_DECR) {
if (rw_lock_get_waiters(lock)) { if (rw_lock_get_waiters(lock)) {
fputs(" Waiters for the lock exist\n", stderr); fputs(" Waiters for the lock exist\n", stderr);
...@@ -874,6 +978,9 @@ rw_lock_print( ...@@ -874,6 +978,9 @@ rw_lock_print(
info = UT_LIST_GET_NEXT(list, info); info = UT_LIST_GET_NEXT(list, info);
} }
} }
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
mutex_exit(&(lock->mutex));
#endif
} }
/************************************************************************* /*************************************************************************
...@@ -922,14 +1029,11 @@ rw_lock_n_locked(void) ...@@ -922,14 +1029,11 @@ rw_lock_n_locked(void)
lock = UT_LIST_GET_FIRST(rw_lock_list); lock = UT_LIST_GET_FIRST(rw_lock_list);
while (lock != NULL) { while (lock != NULL) {
mutex_enter(rw_lock_get_mutex(lock));
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) if (lock->lock_word != X_LOCK_DECR) {
|| (rw_lock_get_reader_count(lock) != 0)) {
count++; count++;
} }
mutex_exit(rw_lock_get_mutex(lock));
lock = UT_LIST_GET_NEXT(list, lock); lock = UT_LIST_GET_NEXT(list, lock);
} }
......
...@@ -5,6 +5,38 @@ Mutex, the basic synchronization primitive ...@@ -5,6 +5,38 @@ Mutex, the basic synchronization primitive
Created 9/5/1995 Heikki Tuuri Created 9/5/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
/***********************************************************************
# Copyright (c) 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
# * Neither the name of the Google Inc. nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Note, the BSD license applies to the new code. The old code is GPL.
***********************************************************************/
#include "sync0sync.h" #include "sync0sync.h"
#ifdef UNIV_NONINL #ifdef UNIV_NONINL
...@@ -138,18 +170,13 @@ Therefore, this thread is guaranteed to catch the os_set_event() ...@@ -138,18 +170,13 @@ Therefore, this thread is guaranteed to catch the os_set_event()
signalled unconditionally at the release of the lock. signalled unconditionally at the release of the lock.
Q.E.D. */ Q.E.D. */
/* The number of system calls made in this module. Intended for performance
monitoring. */
UNIV_INTERN ulint mutex_system_call_count = 0;
/* Number of spin waits on mutexes: for performance monitoring */ /* Number of spin waits on mutexes: for performance monitoring */
/* round=one iteration of a spin loop */ /* round=one iteration of a spin loop */
UNIV_INTERN ulint mutex_spin_round_count = 0; UNIV_INTERN ib_int64_t mutex_spin_round_count = 0;
UNIV_INTERN ulint mutex_spin_wait_count = 0; UNIV_INTERN ib_int64_t mutex_spin_wait_count = 0;
UNIV_INTERN ulint mutex_os_wait_count = 0; UNIV_INTERN ib_int64_t mutex_os_wait_count = 0;
UNIV_INTERN ulint mutex_exit_count = 0; UNIV_INTERN ib_int64_t mutex_exit_count = 0;
/* The global array of wait cells for implementation of the database's own /* The global array of wait cells for implementation of the database's own
mutexes and read-write locks */ mutexes and read-write locks */
...@@ -219,6 +246,8 @@ mutex_create_func( ...@@ -219,6 +246,8 @@ mutex_create_func(
{ {
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER) #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
mutex_reset_lock_word(mutex); mutex_reset_lock_word(mutex);
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
mutex_reset_lock_word(mutex);
#else #else
os_fast_mutex_init(&(mutex->os_fast_mutex)); os_fast_mutex_init(&(mutex->os_fast_mutex));
mutex->lock_word = 0; mutex->lock_word = 0;
...@@ -309,7 +338,9 @@ mutex_free( ...@@ -309,7 +338,9 @@ mutex_free(
os_event_free(mutex->event); os_event_free(mutex->event);
#if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
#else
os_fast_mutex_free(&(mutex->os_fast_mutex)); os_fast_mutex_free(&(mutex->os_fast_mutex));
#endif #endif
/* If we free the mutex protecting the mutex list (freeing is /* If we free the mutex protecting the mutex list (freeing is
...@@ -426,6 +457,12 @@ mutex_spin_wait( ...@@ -426,6 +457,12 @@ mutex_spin_wait(
#endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */ #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
ut_ad(mutex); ut_ad(mutex);
/* This update is not thread safe, but we don't mind if the count
isn't exact. Moved out of ifdef that follows because we are willing
to sacrifice the cost of counting this as the data is valuable.
Count the number of calls to mutex_spin_wait. */
mutex_spin_wait_count++;
mutex_loop: mutex_loop:
i = 0; i = 0;
...@@ -438,7 +475,6 @@ mutex_loop: ...@@ -438,7 +475,6 @@ mutex_loop:
spin_loop: spin_loop:
#if defined UNIV_DEBUG && !defined UNIV_HOTBACKUP #if defined UNIV_DEBUG && !defined UNIV_HOTBACKUP
mutex_spin_wait_count++;
mutex->count_spin_loop++; mutex->count_spin_loop++;
#endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */ #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
...@@ -503,8 +539,6 @@ spin_loop: ...@@ -503,8 +539,6 @@ spin_loop:
sync_array_reserve_cell(sync_primary_wait_array, mutex, sync_array_reserve_cell(sync_primary_wait_array, mutex,
SYNC_MUTEX, file_name, line, &index); SYNC_MUTEX, file_name, line, &index);
mutex_system_call_count++;
/* The memory order of the array reservation and the change in the /* The memory order of the array reservation and the change in the
waiters field is important: when we suspend a thread, we first waiters field is important: when we suspend a thread, we first
reserve the cell and then set waiters field to 1. When threads are reserve the cell and then set waiters field to 1. When threads are
...@@ -551,7 +585,6 @@ spin_loop: ...@@ -551,7 +585,6 @@ spin_loop:
mutex->cfile_name, (ulong) mutex->cline, (ulong) i); mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
#endif #endif
mutex_system_call_count++;
mutex_os_wait_count++; mutex_os_wait_count++;
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
...@@ -1340,21 +1373,31 @@ sync_print_wait_info( ...@@ -1340,21 +1373,31 @@ sync_print_wait_info(
FILE* file) /* in: file where to print */ FILE* file) /* in: file where to print */
{ {
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
fprintf(file, "Mutex exits %lu, rws exits %lu, rwx exits %lu\n", fprintf(file, "Mutex exits %llu, rws exits %llu, rwx exits %llu\n",
mutex_exit_count, rw_s_exit_count, rw_x_exit_count); mutex_exit_count, rw_s_exit_count, rw_x_exit_count);
#endif #endif
fprintf(file, fprintf(file,
"Mutex spin waits %lu, rounds %lu, OS waits %lu\n" "Mutex spin waits %llu, rounds %llu, OS waits %llu\n"
"RW-shared spins %lu, OS waits %lu;" "RW-shared spins %llu, OS waits %llu;"
" RW-excl spins %lu, OS waits %lu\n", " RW-excl spins %llu, OS waits %llu\n",
(ulong) mutex_spin_wait_count, mutex_spin_wait_count,
(ulong) mutex_spin_round_count, mutex_spin_round_count,
(ulong) mutex_os_wait_count, mutex_os_wait_count,
(ulong) rw_s_spin_wait_count, rw_s_spin_wait_count,
(ulong) rw_s_os_wait_count, rw_s_os_wait_count,
(ulong) rw_x_spin_wait_count, rw_x_spin_wait_count,
(ulong) rw_x_os_wait_count); rw_x_os_wait_count);
fprintf(file,
"Spin rounds per wait: %.2f mutex, %.2f RW-shared, "
"%.2f RW-excl\n",
(double) mutex_spin_round_count /
(mutex_spin_wait_count ? mutex_spin_wait_count : 1),
(double) rw_s_spin_round_count /
(rw_s_spin_wait_count ? rw_s_spin_wait_count : 1),
(double) rw_x_spin_round_count /
(rw_x_spin_wait_count ? rw_x_spin_wait_count : 1));
} }
/*********************************************************************** /***********************************************************************
......
...@@ -15,6 +15,7 @@ Created 5/11/1994 Heikki Tuuri ...@@ -15,6 +15,7 @@ Created 5/11/1994 Heikki Tuuri
#include "mem0mem.h" #include "mem0mem.h"
#include "os0sync.h" #include "os0sync.h"
#include "os0thread.h" #include "os0thread.h"
#include "srv0srv.h"
/* This struct is placed first in every allocated memory block */ /* This struct is placed first in every allocated memory block */
typedef struct ut_mem_block_struct ut_mem_block_t; typedef struct ut_mem_block_struct ut_mem_block_t;
...@@ -68,14 +69,29 @@ ut_malloc_low( ...@@ -68,14 +69,29 @@ ut_malloc_low(
ibool assert_on_error)/* in: if TRUE, we crash mysqld if the ibool assert_on_error)/* in: if TRUE, we crash mysqld if the
memory cannot be allocated */ memory cannot be allocated */
{ {
ulint retry_count = 0; ulint retry_count;
void* ret; void* ret;
if (srv_use_sys_malloc) {
ret = malloc(n);
ut_a(ret || !assert_on_error);
#ifdef UNIV_SET_MEM_TO_ZERO
if (set_to_zero) {
memset(ret, '\0', n);
UNIV_MEM_ALLOC(ret, n);
}
#endif
return(ret);
}
ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */ ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
if (!ut_mem_block_list_inited) { if (UNIV_UNLIKELY(!ut_mem_block_list_inited)) {
ut_mem_block_list_init(); ut_mem_block_list_init();
} }
retry_count = 0;
retry: retry:
os_fast_mutex_lock(&ut_list_mutex); os_fast_mutex_lock(&ut_list_mutex);
...@@ -239,6 +255,11 @@ ut_free( ...@@ -239,6 +255,11 @@ ut_free(
{ {
ut_mem_block_t* block; ut_mem_block_t* block;
if (srv_use_sys_malloc) {
free(ptr);
return;
}
block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t)); block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
os_fast_mutex_lock(&ut_list_mutex); os_fast_mutex_lock(&ut_list_mutex);
...@@ -291,6 +312,10 @@ ut_realloc( ...@@ -291,6 +312,10 @@ ut_realloc(
ulint min_size; ulint min_size;
void* new_ptr; void* new_ptr;
if (srv_use_sys_malloc) {
return(realloc(ptr, size));
}
if (ptr == NULL) { if (ptr == NULL) {
return(ut_malloc(size)); return(ut_malloc(size));
...@@ -338,6 +363,11 @@ ut_free_all_mem(void) ...@@ -338,6 +363,11 @@ ut_free_all_mem(void)
{ {
ut_mem_block_t* block; ut_mem_block_t* block;
if (!ut_mem_block_list_inited) {
return;
}
ut_mem_block_list_inited = FALSE;
os_fast_mutex_free(&ut_list_mutex); os_fast_mutex_free(&ut_list_mutex);
while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) { while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) {
......
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