Beispiel #1
0
ibool
rw_lock_own(
    /*========*/
    /* out: TRUE if locked */
    rw_lock_t*	lock,		/* in: rw-lock */
    ulint		lock_type)	/* in: lock type: RW_LOCK_SHARED,
					RW_LOCK_EX */
{
    rw_lock_debug_t*	info;

    ut_ad(lock);
    ut_ad(rw_lock_validate(lock));

    mutex_enter(&(lock->mutex));

    info = UT_LIST_GET_FIRST(lock->debug_list);

    while (info != NULL) {

        if (os_thread_eq(info->thread_id, os_thread_get_curr_id())
                && (info->pass == 0)
                && (info->lock_type == lock_type)) {

            mutex_exit(&(lock->mutex));
            /* Found! */

            return(TRUE);
        }

        info = UT_LIST_GET_NEXT(list, info);
    }
    mutex_exit(&(lock->mutex));

    return(FALSE);
}
Beispiel #2
0
trx_t*
trx_allocate_for_mysql(void)
/*========================*/
				/* out, own: transaction object */
{
	trx_t*	trx;

	mutex_enter(&kernel_mutex);

	/* Open a dummy session */

	if (!trx_dummy_sess) {
		trx_dummy_sess = sess_open();
	}

	trx = trx_create(trx_dummy_sess);

	trx_n_mysql_transactions++;

	UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx);

	mutex_exit(&kernel_mutex);

	trx->mysql_thread_id = os_thread_get_curr_id();

	trx->mysql_process_no = os_proc_get_number();

	return(trx);
}
Beispiel #3
0
/*************************************************************//**
Report a failed assertion. */
UNIV_INTERN
void
ut_dbg_assertion_failed(
/*====================*/
	const char* expr,	/*!< in: the failed assertion (optional) */
	const char* file,	/*!< in: source file containing the assertion */
	ulint line)		/*!< in: line number of the assertion */
{
	ut_print_timestamp(stderr);
#ifdef UNIV_HOTBACKUP
	fprintf(stderr, "  InnoDB: Assertion failure in file %s line %lu\n",
		file, line);
#else /* UNIV_HOTBACKUP */
	fprintf(stderr,
		"  InnoDB: Assertion failure in thread %lu"
		" in file %s line %lu\n",
		os_thread_pf(os_thread_get_curr_id()),
		innobase_basename(file), line);
#endif /* UNIV_HOTBACKUP */
	if (expr) {
		fprintf(stderr,
			"InnoDB: Failing assertion: %s\n", expr);
	}

	fputs("InnoDB: We intentionally generate a memory trap.\n"
	      "InnoDB: Submit a detailed bug report"
	      " to http://bugs.mysql.com.\n"
	      "InnoDB: If you get repeated assertion failures"
	      " or crashes, even\n"
	      "InnoDB: immediately after the mysqld startup, there may be\n"
	      "InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
	      "InnoDB: " REFMAN "forcing-innodb-recovery.html\n"
	      "InnoDB: about forcing recovery.\n", stderr);
}
/************************************************************************
I/o-handler thread function. */
static

os_thread_ret_t
io_handler_thread(
/*==============*/
	void*	arg)
{
	ulint	segment;
	ulint	i;

	segment = *((ulint*)arg);

#ifdef UNIV_DEBUG_THREAD_CREATION
	fprintf(stderr, "Io handler thread %lu starts, id %lu\n", segment,
		os_thread_pf(os_thread_get_curr_id()));
#endif
	for (i = 0;; i++) {
		fil_aio_wait(segment);

		mutex_enter(&ios_mutex);
		ios++;
		mutex_exit(&ios_mutex);
	}

	/* We count the number of threads in os_thread_exit(). A created
	thread should always use that to exit and not use return() to exit.
	The thread actually never comes here because it is exited in an
	os_event_wait(). */

	os_thread_exit(NULL);

	OS_THREAD_DUMMY_RETURN;
}
Beispiel #5
0
/*****************************************************************//**
Exits the current thread. */
UNIV_INTERN
void
os_thread_exit(
/*===========*/
	void*	exit_value)	/*!< in: exit value; in Windows this void*
				is cast as a DWORD */
{
#ifndef __WIN__
	int	ret;
#endif /* __WIN__ */

#ifdef UNIV_DEBUG_THREAD_CREATION
	ib_logger(ib_stream, "Thread exits, id %lu\n",
		os_thread_pf(os_thread_get_curr_id()));
#endif /* UNIV_DEBUG_THREAD_CREATION */

	os_mutex_enter(os_sync_mutex);
	os_thread_count--;
	os_mutex_exit(os_sync_mutex);

#ifdef __WIN__
	ExitThread((DWORD)exit_value);
#else
	ret = pthread_detach(pthread_self());
	ut_a(ret == 0);

	pthread_exit(exit_value);
#endif /* __WIN__ */
}
Beispiel #6
0
/*****************************************************************//**
Exits the current thread. */
UNIV_INTERN
void
os_thread_exit(
/*===========*/
	void*	exit_value)	/*!< in: exit value; in Windows this void*
				is cast as a DWORD */
{
#ifdef UNIV_DEBUG_THREAD_CREATION
	fprintf(stderr, "Thread exits, id %lu\n",
		os_thread_pf(os_thread_get_curr_id()));
#endif

#ifdef UNIV_PFS_THREAD
	pfs_delete_thread();
#endif

	os_mutex_enter(os_sync_mutex);
	os_thread_count--;
	os_mutex_exit(os_sync_mutex);

#ifdef __WIN__
	ExitThread((DWORD)exit_value);
#else
	pthread_detach(pthread_self());
	pthread_exit(exit_value);
#endif
}
Beispiel #7
0
void
rw_lock_add_debug_info(
    /*===================*/
    rw_lock_t*	lock,		/* in: rw-lock */
    ulint		pass,		/* in: pass value */
    ulint		lock_type,	/* in: lock type */
    const char*	file_name,	/* in: file where requested */
    ulint		line)		/* in: line where requested */
{
    rw_lock_debug_t*	info;

    ut_ad(lock);
    ut_ad(file_name);

    info = rw_lock_debug_create();

    rw_lock_debug_mutex_enter();

    info->file_name = file_name;
    info->line	= line;
    info->lock_type = lock_type;
    info->thread_id = os_thread_get_curr_id();
    info->pass	= pass;

    UT_LIST_ADD_FIRST(list, lock->debug_list, info);

    rw_lock_debug_mutex_exit();

    if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
        sync_thread_add_level(lock, lock->level);
    }
}
Beispiel #8
0
void
ut_dbg_assertion_failed(
/*====================*/
	const char* expr,	/* in: the failed assertion (optional) */
	const char* file,	/* in: source file containing the assertion */
	ulint line)		/* in: line number of the assertion */
{
	ut_print_timestamp(stderr);
	fprintf(stderr,
		"InnoDB: Assertion failure in thread %lu"
		" in file %s line %lu\n",
		os_thread_pf(os_thread_get_curr_id()), file, line);
	if (expr) {
		fprintf(stderr,
			"InnoDB: Failing assertion: %s\n", expr);
	}

	fputs(
"InnoDB: We intentionally generate a memory trap.\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com.\n"
"InnoDB: If you get repeated assertion failures or crashes, even\n"
"InnoDB: immediately after the mysqld startup, there may be\n"
"InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
"InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
	ut_dbg_stop_threads = TRUE;
}
Beispiel #9
0
void
sync_array_wait_event(
/*==================*/
	sync_array_t*	arr,	/* in: wait array */
	ulint		index)	/* in: index of the reserved cell */
{
	sync_cell_t*	cell;
	os_event_t	event;

	ut_a(arr);

	sync_array_enter(arr);

	cell = sync_array_get_nth_cell(arr, index);

	ut_a(cell->wait_object);
	ut_a(!cell->waiting);
	ut_ad(os_thread_get_curr_id() == cell->thread);

	if (cell->request_type == SYNC_MUTEX) {
		event = ((mutex_t*) cell->wait_object)->event;
#ifdef __WIN__
	/* On windows if the thread about to wait is the one which
	has set the state of the rw_lock to RW_LOCK_WAIT_EX, then
	it waits on a special event i.e.: wait_ex_event. */
	} else if (cell->request_type == RW_LOCK_WAIT_EX) {
		event = ((rw_lock_t*) cell->wait_object)->wait_ex_event;
#endif
	} else {
		event = ((rw_lock_t*) cell->wait_object)->event;
	}

		cell->waiting = TRUE;

#ifdef UNIV_SYNC_DEBUG

	/* We use simple enter to the mutex below, because if
	we cannot acquire it at once, mutex_enter would call
	recursively sync_array routines, leading to trouble.
	rw_lock_debug_mutex freezes the debug lists. */

	rw_lock_debug_mutex_enter();

	if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) {

		fputs("########################################\n", stderr);
		ut_error;
	}

	rw_lock_debug_mutex_exit();
#endif
	sync_array_exit(arr);

	os_event_wait_low(event, cell->signal_count);

	sync_array_free_cell(arr, index);
}
Beispiel #10
0
void
ut_dbg_stop_thread(
/*===============*/
	const char*	file,
	ulint		line)
{
	fprintf(stderr, "InnoDB: Thread %lu stopped in file %s line %lu\n",
		os_thread_pf(os_thread_get_curr_id()), file, line);
	os_thread_sleep(1000000000);
}
Beispiel #11
0
/*************************************************************//**
Stop a thread after assertion failure. */
UNIV_INTERN
void
ut_dbg_stop_thread(
/*===============*/
	const char*	file,
	ulint		line)
{
#ifndef UNIV_HOTBACKUP
	fprintf(stderr, "InnoDB: Thread %lu stopped in file %s line %lu\n",
		os_thread_pf(os_thread_get_curr_id()), file, line);
	os_thread_sleep(1000000000);
#endif /* !UNIV_HOTBACKUP */
}
Beispiel #12
0
/******************************************************************//**
Low-level function for acquiring an exclusive lock.
@return	RW_LOCK_NOT_LOCKED if did not succeed, RW_LOCK_EX if success. */
UNIV_INLINE
ibool
rw_lock_x_lock_low(
/*===============*/
	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();

	if (rw_lock_lock_word_decr(lock, X_LOCK_DECR)) {

		/* lock->recursive also tells us if the writer_thread
		field is stale or active. As we are going to write
		our own thread id in that field it must be that the
		current writer_thread value is not active. */
		ut_a(!lock->recursive);

		/* 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
				    pass,
#endif
                                    file_name, line);

	} else {
		/* Decrement failed: relock or failed lock */
		if (!pass && lock->recursive
		    && os_thread_eq(lock->writer_thread, curr_thread)) {
			/* 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;

	return(TRUE);
}
Beispiel #13
0
void
rw_lock_x_lock_move_ownership(
    /*==========================*/
    rw_lock_t*	lock)	/* in: lock which was x-locked in the
				buffer read */
{
    ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));

    mutex_enter(&(lock->mutex));

    lock->writer_thread = os_thread_get_curr_id();

    lock->pass = 0;

    mutex_exit(&(lock->mutex));
}
Beispiel #14
0
/******************************************************************//**
This function should be called when a thread starts to wait on
a wait array cell. In the debug version this function checks
if the wait for a semaphore will result in a deadlock, in which
case prints info and asserts. */
UNIV_INTERN
void
sync_array_wait_event(
/*==================*/
	sync_array_t*	arr,	/*!< in: wait array */
	ulint		index)	/*!< in: index of the reserved cell */
{
	sync_cell_t*	cell;
	os_event_t	event;

	ut_a(arr);

	sync_array_enter(arr);

	cell = sync_array_get_nth_cell(arr, index);

	ut_a(cell->wait_object);
	ut_a(!cell->waiting);
	ut_ad(os_thread_get_curr_id() == cell->thread);

	event = sync_cell_get_event(cell);
		cell->waiting = TRUE;

#ifdef UNIV_SYNC_DEBUG

	/* We use simple enter to the mutex below, because if
	we cannot acquire it at once, mutex_enter would call
	recursively sync_array routines, leading to trouble.
	rw_lock_debug_mutex freezes the debug lists. */

	rw_lock_debug_mutex_enter();

	if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) {

		fputs("########################################\n", stderr);
		ut_error;
	}

	rw_lock_debug_mutex_exit();
#endif
	sync_array_exit(arr);

	os_event_wait_low(event, cell->signal_count);

	sync_array_free_cell(arr, index);
}
Beispiel #15
0
/******************************************************************//**
Removes a debug information struct for an rw-lock. */
UNIV_INTERN
void
rw_lock_remove_debug_info(
/*======================*/
	rw_lock_t*	lock,		/*!< in: rw-lock */
	ulint		pass,		/*!< in: pass value */
	ulint		lock_type)	/*!< in: lock type */
{
	rw_lock_debug_t*	info;

	ut_ad(lock);

	if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
		sync_thread_reset_level(lock);
	}

	rw_lock_debug_mutex_enter();

	info = UT_LIST_GET_FIRST(lock->debug_list);

	while (info != NULL) {
		if ((pass == info->pass)
		    && ((pass != 0)
			|| os_thread_eq(info->thread_id,
					os_thread_get_curr_id()))
		    && (info->lock_type == lock_type)) {

			/* Found! */
			UT_LIST_REMOVE(list, lock->debug_list, info);
			rw_lock_debug_mutex_exit();

			rw_lock_debug_free(info);

			return;
		}

		info = UT_LIST_GET_NEXT(list, info);
	}

	ut_error;
}
Beispiel #16
0
/********************************************************************//**
Creates a transaction object for MySQL.
@return	own: transaction object */
UNIV_INTERN
trx_t*
trx_allocate_for_mysql(void)
/*========================*/
{
	trx_t*	trx;

	mutex_enter(&kernel_mutex);

	trx = trx_create(trx_dummy_sess);

	trx_n_mysql_transactions++;

	UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx);

	mutex_exit(&kernel_mutex);

	trx->mysql_thread_id = os_thread_get_curr_id();

	trx->mysql_process_no = os_proc_get_number();

	return(trx);
}
Beispiel #17
0
ibool
rw_lock_own(
    /*========*/
    /* out: TRUE if locked */
    rw_lock_t*	lock,		/* in: rw-lock */
    ulint		lock_type)	/* in: lock type */
{
    rw_lock_debug_t*	info;

    ut_ad(lock);
    ut_ad(rw_lock_validate(lock));

#ifndef UNIV_SYNC_DEBUG
    ut_error;
#endif
    mutex_enter(&(lock->mutex));

    info = UT_LIST_GET_FIRST(lock->debug_list);

    while (info != NULL) {

        if ((info->thread_id == os_thread_get_curr_id())
                && (info->pass == 0)
                && (info->lock_type == lock_type)) {

            mutex_exit(&(lock->mutex));
            /* Found! */

            return(TRUE);
        }

        info = UT_LIST_GET_NEXT(list, info);
    }
    mutex_exit(&(lock->mutex));

    return(FALSE);
}
Beispiel #18
0
/*******************************************************************//**
Roll back an active transaction. */
static
void
trx_rollback_active(
/*================*/
	trx_t*	trx)	/*!< in/out: transaction */
{
	mem_heap_t*	heap;
	que_fork_t*	fork;
	que_thr_t*	thr;
	roll_node_t*	roll_node;
	dict_table_t*	table;
	ib_int64_t	rows_to_undo;
	const char*	unit		= "";
	ibool		dictionary_locked = FALSE;

	heap = mem_heap_create(512);

	fork = que_fork_create(NULL, NULL, QUE_FORK_RECOVERY, heap);
	fork->trx = trx;

	thr = que_thr_create(fork, heap);

	roll_node = roll_node_create(heap);

	thr->child = roll_node;
	roll_node->common.parent = thr;

	mutex_enter(&kernel_mutex);

	trx->graph = fork;

	ut_a(thr == que_fork_start_command(fork));

	trx_roll_crash_recv_trx	= trx;
	trx_roll_max_undo_no = trx->undo_no;
	trx_roll_progress_printed_pct = 0;
	rows_to_undo = trx_roll_max_undo_no;

	if (rows_to_undo > 1000000000) {
		rows_to_undo = rows_to_undo / 1000000;
		unit = "M";
	}

	ut_print_timestamp(stderr);
	fprintf(stderr,
		"  InnoDB: Rolling back trx with id " TRX_ID_FMT ", %lu%s"
		" rows to undo\n",
		(ullint) trx->id,
		(ulong) rows_to_undo, unit);
	mutex_exit(&kernel_mutex);

	trx->mysql_thread_id = os_thread_get_curr_id();

	trx->mysql_process_no = os_proc_get_number();

	if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
		row_mysql_lock_data_dictionary(trx);
		dictionary_locked = TRUE;
	}

	que_run_threads(thr);

	mutex_enter(&kernel_mutex);

	while (trx->que_state != TRX_QUE_RUNNING) {

		mutex_exit(&kernel_mutex);

		fprintf(stderr,
			"InnoDB: Waiting for rollback of trx id "
			TRX_ID_FMT " to end\n",
			(ullint) trx->id);
		os_thread_sleep(100000);

		mutex_enter(&kernel_mutex);
	}

	mutex_exit(&kernel_mutex);

	if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE
	    && trx->table_id != 0) {

		/* If the transaction was for a dictionary operation, we
		drop the relevant table, if it still exists */

		fprintf(stderr,
			"InnoDB: Dropping table with id %llu"
			" in recovery if it exists\n",
			(ullint) trx->table_id);

		table = dict_table_get_on_id_low(trx->table_id);

		if (table) {
			ulint	err;

			fputs("InnoDB: Table found: dropping table ", stderr);
			ut_print_name(stderr, trx, TRUE, table->name);
			fputs(" in recovery\n", stderr);

			err = row_drop_table_for_mysql(table->name, trx, TRUE);
			trx_commit_for_mysql(trx);

			ut_a(err == (int) DB_SUCCESS);
		}
	}

	if (dictionary_locked) {
		row_mysql_unlock_data_dictionary(trx);
	}

	fprintf(stderr, "\nInnoDB: Rolling back of trx id " TRX_ID_FMT
		" completed\n",
		(ullint) trx->id);
	mem_heap_free(heap);

	trx_roll_crash_recv_trx	= NULL;
}
Beispiel #19
0
/******************************************************************//**
Lock an rw-lock in shared mode for the current thread. If the rw-lock is
locked in exclusive mode, or there is an exclusive lock request waiting,
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
for the lock, before suspending the thread. */
UNIV_INTERN
void
rw_lock_s_lock_spin(
/*================*/
	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 */
{
	ulint	 index;	/* index of the reserved wait cell */
	ulint	 i = 0;	/* spin round count */

	ut_ad(rw_lock_validate(lock));

	rw_s_spin_wait_count++;	/*!< Count calls to this function */
lock_loop:

	/* Spin waiting for the writer field to become free */
	while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) {
		if (srv_spin_wait_delay) {
			ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
		}

		i++;
	}

	if (i == SYNC_SPIN_ROUNDS) {
		os_thread_yield();
	}

	if (srv_print_latch_waits) {
		fprintf(stderr,
			"Thread %lu spin wait rw-s-lock at %p"
			" cfile %s cline %lu rnds %lu\n",
			(ulong) os_thread_pf(os_thread_get_curr_id()),
			(void*) lock,
			innobase_basename(lock->cfile_name),
			(ulong) lock->cline, (ulong) i);
	}

	/* We try once again to obtain the lock */
	if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
		rw_s_spin_round_count += i;

		return; /* Success */
	} else {

		if (i < SYNC_SPIN_ROUNDS) {
			goto lock_loop;
		}

		rw_s_spin_round_count += i;

		sync_array_reserve_cell(sync_primary_wait_array,
					lock, RW_LOCK_SHARED,
					file_name, line,
					&index);

		/* 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);

		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) {
			fprintf(stderr,
				"Thread %lu OS wait rw-s-lock at %p"
				" cfile %s cline %lu\n",
				os_thread_pf(os_thread_get_curr_id()),
				(void*) lock,
				innobase_basename(lock->cfile_name),
				(ulong) lock->cline);
		}

		/* these stats may not be accurate */
		lock->count_os_wait++;
		rw_s_os_wait_count++;

		sync_array_wait_event(sync_primary_wait_array, index);

		i = 0;
		goto lock_loop;
	}
}
Beispiel #20
0
/******************************************************************//**
Reserves a wait array cell for waiting for an object.
The event of the cell is reset to nonsignalled state. */
UNIV_INTERN
void
sync_array_reserve_cell(
/*====================*/
	sync_array_t*	arr,	/*!< in: wait array */
	void*		object, /*!< in: pointer to the object to wait for */
	ulint		type,	/*!< in: lock request type */
	const char*	file,	/*!< in: file where requested */
	ulint		line,	/*!< in: line where requested */
	ulint*		index)	/*!< out: index of the reserved cell */
{
	sync_cell_t*	cell;
	os_event_t      event;
	ulint		i;

	ut_a(object);
	ut_a(index);

	sync_array_enter(arr);

	arr->res_count++;

	/* Reserve a new cell. */
	for (i = 0; i < arr->n_cells; i++) {
		cell = sync_array_get_nth_cell(arr, i);

		if (cell->wait_object == NULL) {

			cell->waiting = FALSE;
			cell->wait_object = object;

			if (type == SYNC_MUTEX) {
				cell->old_wait_mutex = object;
			} else {
				cell->old_wait_rw_lock = object;
			}

			cell->request_type = type;

			cell->file = file;
			cell->line = line;

			arr->n_reserved++;

			*index = i;

			sync_array_exit(arr);

			/* Make sure the event is reset and also store
			the value of signal_count at which the event
			was reset. */
                        event = sync_cell_get_event(cell);
			cell->signal_count = os_event_reset(event);

			cell->reservation_time = time(NULL);

			cell->thread = os_thread_get_curr_id();

			return;
		}
	}

	ut_error; /* No free cell found */

	return;
}
Beispiel #21
0
/******************************************************************//**
NOTE! Use the corresponding macro, not directly this function! Lock an
rw-lock in exclusive mode for the current thread. If the rw-lock is locked
in shared or exclusive mode, or there is an exclusive lock request waiting,
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
for the lock before suspending the thread. If the same thread has an x-lock
on the rw-lock, locking succeed, with the following exception: if pass != 0,
only a single x-lock may be taken on the lock. NOTE: If the same thread has
an s-lock, locking does not succeed! */
UNIV_INTERN
void
rw_lock_x_lock_func(
/*================*/
	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 */
{
	ulint	index;	/*!< index of the reserved wait cell */
	ulint	i;	/*!< spin round count */
	ibool	spinning = FALSE;

	ut_ad(rw_lock_validate(lock));
#ifdef UNIV_SYNC_DEBUG
	ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */

	i = 0;

lock_loop:

	if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
		rw_x_spin_round_count += i;

		return;	/* Locking succeeded */

	} else {

                if (!spinning) {
                        spinning = TRUE;
                        rw_x_spin_wait_count++;
		}

		/* Spin waiting for the lock_word to become free */
		while (i < SYNC_SPIN_ROUNDS
		       && lock->lock_word <= 0) {
			if (srv_spin_wait_delay) {
				ut_delay(ut_rnd_interval(0,
							 srv_spin_wait_delay));
			}

			i++;
		}
		if (i == SYNC_SPIN_ROUNDS) {
			os_thread_yield();
		} else {
			goto lock_loop;
		}
	}

	rw_x_spin_round_count += i;

	if (srv_print_latch_waits) {
		fprintf(stderr,
			"Thread %lu spin wait rw-x-lock at %p"
			" cfile %s cline %lu rnds %lu\n",
			os_thread_pf(os_thread_get_curr_id()), (void*) lock,
			innobase_basename(lock->cfile_name),
			(ulong) lock->cline, (ulong) i);
	}

	sync_array_reserve_cell(sync_primary_wait_array,
				lock,
				RW_LOCK_EX,
				file_name, line,
				&index);

	/* 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);

	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) {
		fprintf(stderr,
			"Thread %lu OS wait for rw-x-lock at %p"
			" cfile %s cline %lu\n",
			os_thread_pf(os_thread_get_curr_id()), (void*) lock,
			innobase_basename(lock->cfile_name),
			(ulong) lock->cline);
	}

	/* these stats may not be accurate */
	lock->count_os_wait++;
	rw_x_os_wait_count++;

	sync_array_wait_event(sync_primary_wait_array, index);

	i = 0;
	goto lock_loop;
}
Beispiel #22
0
enum db_err
ib_trx_lock_table_with_retry(
/*=========================*/
	trx_t*		trx,		/*!< in/out: transaction */
	dict_table_t*	table,		/*!< in: table to lock */
	enum lock_mode	mode)		/*!< in: LOCK_X or LOCK_S */
{
	que_thr_t*	thr;
	enum db_err	err;
	mem_heap_t*	heap;
	sel_node_t*	node;

	ut_ad(trx->client_thread_id == os_thread_get_curr_id());

	heap = mem_heap_create(512);

	trx->op_info = "setting table lock";

	node = sel_node_create(heap);
	thr = pars_complete_graph_for_exec(node, trx, heap);
	thr->graph->state = QUE_FORK_ACTIVE;

	/* We use the select query graph as the dummy graph needed
	in the lock module call */

	thr = que_fork_get_first_thr(que_node_get_parent(thr));
	que_thr_move_to_run_state(thr);

run_again:
	thr->run_node = thr;
	thr->prev_node = thr->common.parent;

	err = lock_table(0, table, mode, thr);

	trx->error_state = err;

	if (UNIV_LIKELY(err == DB_SUCCESS)) {
		que_thr_stop_for_client_no_error(thr, trx);
	} else {
		que_thr_stop_client(thr);

		if (err != DB_QUE_THR_SUSPENDED) {
			ibool	was_lock_wait;

			was_lock_wait = ib_handle_errors(&err, trx, thr, NULL);

			if (was_lock_wait) {
				goto run_again;
			}
		} else {
			que_thr_t*	run_thr;
			que_node_t*	parent;

			parent = que_node_get_parent(thr);
			run_thr = que_fork_start_command(parent);

			ut_a(run_thr == thr);

			/* There was a lock wait but the thread was not
			in a ready to run or running state. */
			trx->error_state = DB_LOCK_WAIT;

			goto run_again;
		}
	}

	que_graph_free(thr->graph);
	trx->op_info = "";

	return(err);
}
Beispiel #23
0
void
rw_lock_s_lock_spin(
    /*================*/
    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 */
{
    ulint	 index;	/* index of the reserved wait cell */
    ulint	 i;	/* spin round count */

    ut_ad(rw_lock_validate(lock));

lock_loop:
    rw_s_spin_wait_count++;

    /* Spin waiting for the writer field to become free */
    i = 0;

    while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
            && i < SYNC_SPIN_ROUNDS) {
        if (srv_spin_wait_delay) {
            ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
        }

        i++;
    }

    if (i == SYNC_SPIN_ROUNDS) {
        os_thread_yield();
    }

    if (srv_print_latch_waits) {
        fprintf(stderr,
                "Thread %lu spin wait rw-s-lock at %p"
                " cfile %s cline %lu rnds %lu\n",
                (ulong) os_thread_pf(os_thread_get_curr_id()),
                (void*) lock,
                lock->cfile_name, (ulong) lock->cline, (ulong) i);
    }

    mutex_enter(rw_lock_get_mutex(lock));

    /* We try once again to obtain the lock */

    if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
        mutex_exit(rw_lock_get_mutex(lock));

        return; /* Success */
    } 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++;

        sync_array_reserve_cell(sync_primary_wait_array,
                                lock, RW_LOCK_SHARED,
                                file_name, line,
                                &index);

        rw_lock_set_waiters(lock, 1);

        mutex_exit(rw_lock_get_mutex(lock));

        if (srv_print_latch_waits) {
            fprintf(stderr,
                    "Thread %lu OS wait rw-s-lock at %p"
                    " cfile %s cline %lu\n",
                    os_thread_pf(os_thread_get_curr_id()),
                    (void*) lock, lock->cfile_name,
                    (ulong) lock->cline);
        }

        rw_s_system_call_count++;
        rw_s_os_wait_count++;

        sync_array_wait_event(sync_primary_wait_array, index);

        goto lock_loop;
    }
}
Beispiel #24
0
/**********************************************************************
Low-level function for acquiring an exclusive lock. */
UNIV_INLINE
ulint
rw_lock_x_lock_low(
    /*===============*/
    /* 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 */
    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 */
{
    ut_ad(mutex_own(rw_lock_get_mutex(lock)));

    if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) {

        if (rw_lock_get_reader_count(lock) == 0) {

            rw_lock_set_writer(lock, RW_LOCK_EX);
            lock->writer_thread = os_thread_get_curr_id();
            lock->writer_count++;
            lock->pass = pass;

#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 succeeded, we may return */
            return(RW_LOCK_EX);
        } else {
            /* 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;

#ifdef UNIV_SYNC_DEBUG
            rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
                                   file_name, line);
#endif

            return(RW_LOCK_WAIT_EX);
        }

    } 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
            rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX);
            rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
                                   file_name, line);
#endif

            lock->last_x_file_name = file_name;
            lock->last_x_line = (unsigned int) line;

            /* Locking succeeded, we may return */
            return(RW_LOCK_EX);
        }

        return(RW_LOCK_WAIT_EX);

    } else if ((rw_lock_get_writer(lock) == RW_LOCK_EX)
               && os_thread_eq(lock->writer_thread,
                               os_thread_get_curr_id())
               && (lock->pass == 0)
               && (pass == 0)) {

        lock->writer_count++;

#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 succeeded, we may return */
        return(RW_LOCK_EX);
    }

    /* Locking did not succeed */
    return(RW_LOCK_NOT_LOCKED);
}
Beispiel #25
0
void
rw_lock_x_lock_func(
    /*================*/
    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 */
{
    ulint	index;	/* index of the reserved wait cell */
    ulint	state;	/* lock state acquired */
    ulint	i;	/* spin round count */

    ut_ad(rw_lock_validate(lock));

lock_loop:
    /* 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));

    if (state == RW_LOCK_EX) {

        return;	/* Locking succeeded */

    } else if (state == RW_LOCK_NOT_LOCKED) {

        /* Spin waiting for the writer field to become free */
        i = 0;

        while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
                && i < SYNC_SPIN_ROUNDS) {
            if (srv_spin_wait_delay) {
                ut_delay(ut_rnd_interval(0,
                                         srv_spin_wait_delay));
            }

            i++;
        }
        if (i == SYNC_SPIN_ROUNDS) {
            os_thread_yield();
        }
    } else if (state == RW_LOCK_WAIT_EX) {

        /* Spin waiting for the reader count field to become zero */
        i = 0;

        while (rw_lock_get_reader_count(lock) != 0
                && i < SYNC_SPIN_ROUNDS) {
            if (srv_spin_wait_delay) {
                ut_delay(ut_rnd_interval(0,
                                         srv_spin_wait_delay));
            }

            i++;
        }
        if (i == SYNC_SPIN_ROUNDS) {
            os_thread_yield();
        }
    } else {
        i = 0; /* Eliminate a compiler warning */
        ut_error;
    }

    if (srv_print_latch_waits) {
        fprintf(stderr,
                "Thread %lu spin wait rw-x-lock at %p"
                " cfile %s cline %lu rnds %lu\n",
                os_thread_pf(os_thread_get_curr_id()), (void*) lock,
                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,
                            lock,
#ifdef __WIN__
                            /* On windows RW_LOCK_WAIT_EX signifies
                            that this thread should wait on the
                            special wait_ex_event. */
                            (state == RW_LOCK_WAIT_EX)
                            ? RW_LOCK_WAIT_EX :
#endif
                            RW_LOCK_EX,
                            file_name, line,
                            &index);

    rw_lock_set_waiters(lock, 1);

    mutex_exit(rw_lock_get_mutex(lock));

    if (srv_print_latch_waits) {
        fprintf(stderr,
                "Thread %lu OS wait for rw-x-lock at %p"
                " cfile %s cline %lu\n",
                os_thread_pf(os_thread_get_curr_id()), (void*) lock,
                lock->cfile_name, (ulong) lock->cline);
    }

    rw_x_system_call_count++;
    rw_x_os_wait_count++;

    sync_array_wait_event(sync_primary_wait_array, index);

    goto lock_loop;
}