read0read.c 6.39 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/******************************************************
Cursor read

(c) 1997 Innobase Oy

Created 2/16/1997 Heikki Tuuri
*******************************************************/

#include "read0read.h"

#ifdef UNIV_NONINL
#include "read0read.ic"
#endif

#include "srv0srv.h"
#include "trx0sys.h"

/*************************************************************************
Creates a read view object. */
UNIV_INLINE
read_view_t*
read_view_create_low(
/*=================*/
				/* out, own: read view struct */
	ulint		n,	/* in: number of cells in the trx_ids array */
	mem_heap_t*	heap)	/* in: memory heap from which allocated */
{
	read_view_t*	view;

	view = mem_heap_alloc(heap, sizeof(read_view_t));

	view->n_trx_ids = n;
	view->trx_ids = mem_heap_alloc(heap, n * sizeof(dulint));

	return(view);
}

/*************************************************************************
Makes a copy of the oldest existing read view, with the exception that also
the creating trx of the oldest view is set as not visible in the 'copied'
monty@donna.mysql.fi's avatar
Merge  
monty@donna.mysql.fi committed
41 42
view. Opens a new view if no views currently exist. The view must be closed
with ..._close. This is used in purge. */
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

read_view_t*
read_view_oldest_copy_or_open_new(
/*==============================*/
				/* out, own: read view struct */
	trx_t*		cr_trx,	/* in: creating transaction, or NULL */
	mem_heap_t*	heap)	/* in: memory heap from which allocated */
{
	read_view_t*	old_view;
	read_view_t*	view_copy;
	ibool		needs_insert	= TRUE;
	ulint		insert_done	= 0;
	ulint		n;
	ulint		i;

58 59 60
#ifdef UNIV_SYNC_DEBUG
	ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
	old_view = UT_LIST_GET_LAST(trx_sys->view_list);

	if (old_view == NULL) {

		return(read_view_open_now(cr_trx, heap));
	}

	n = old_view->n_trx_ids;

	if (old_view->creator) {
		n++;
	} else {
		needs_insert = FALSE;
	}

	view_copy = read_view_create_low(n, heap);
	
	/* Insert the id of the creator in the right place of the descending
	array of ids, if needs_insert is TRUE: */

	i = 0;
	while (i < n) {
		if (needs_insert
		    && (i >= old_view->n_trx_ids
		     || ut_dulint_cmp(old_view->creator->id,
					read_view_get_nth_trx_id(old_view, i))
				> 0)) {

			read_view_set_nth_trx_id(view_copy, i,
						old_view->creator->id);
			needs_insert = FALSE;
			insert_done = 1;
		} else {
			read_view_set_nth_trx_id(view_copy, i,
				read_view_get_nth_trx_id(old_view,
							i - insert_done));
		}

		i++;
	}

	view_copy->creator = cr_trx;
	
  	view_copy->low_limit_no = old_view->low_limit_no;
	view_copy->low_limit_id = old_view->low_limit_id;

	view_copy->can_be_too_old = FALSE;

	if (n > 0) {
		/* The last active transaction has the smallest id: */
		view_copy->up_limit_id = read_view_get_nth_trx_id(
							view_copy, n - 1);
	} else {
		view_copy->up_limit_id = old_view->up_limit_id;
	}

	UT_LIST_ADD_LAST(view_list, trx_sys->view_list, view_copy);

	return(view_copy);
}

/*************************************************************************
Opens a read view where exactly the transactions serialized before this
point in time are seen in the view. */

read_view_t*
read_view_open_now(
/*===============*/
				/* out, own: read view struct */
	trx_t*		cr_trx,	/* in: creating transaction, or NULL */
	mem_heap_t*	heap)	/* in: memory heap from which allocated */
{
	read_view_t*	view;
	trx_t*		trx;
	ulint		n;
136
#ifdef UNIV_SYNC_DEBUG
137
	ut_ad(mutex_own(&kernel_mutex));
138
#endif /* UNIV_SYNC_DEBUG */
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
	view = read_view_create_low(UT_LIST_GET_LEN(trx_sys->trx_list), heap);

	view->creator = cr_trx;

	/* No future transactions should be visible in the view */

  	view->low_limit_no = trx_sys->max_trx_id;
	view->low_limit_id = view->low_limit_no;

	view->can_be_too_old = FALSE;

	n = 0;
	trx = UT_LIST_GET_FIRST(trx_sys->trx_list);

	/* No active transaction should be visible, except cr_trx */

	while (trx) {
156 157
                if (trx != cr_trx && (trx->conc_state == TRX_ACTIVE ||
                                        trx->conc_state == TRX_PREPARED)) {
158 159

			read_view_set_nth_trx_id(view, n, trx->id);
160

161 162 163 164
			n++;

			/* NOTE that a transaction whose trx number is <
			trx_sys->max_trx_id can still be active, if it is
monty@donna.mysql.fi's avatar
Merge  
monty@donna.mysql.fi committed
165
			in the middle of its commit! Note that when a
166 167
			transaction starts, we initialize trx->no to
			ut_dulint_max. */
168

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
			if (ut_dulint_cmp(view->low_limit_no, trx->no) > 0) {

				view->low_limit_no = trx->no;
			}	
		}

		trx = UT_LIST_GET_NEXT(trx_list, trx);
	}

	view->n_trx_ids = n;		

	if (n > 0) {
		/* The last active transaction has the smallest id: */
		view->up_limit_id = read_view_get_nth_trx_id(view, n - 1);
	} else {
		view->up_limit_id = view->low_limit_id;
	}

	UT_LIST_ADD_FIRST(view_list, trx_sys->view_list, view);
	
	return(view);
}

/*************************************************************************
Closes a read view. */

void
read_view_close(
/*============*/
	read_view_t*	view)	/* in: read view */
{
200
#ifdef UNIV_SYNC_DEBUG
201
	ut_ad(mutex_own(&kernel_mutex));
202
#endif /* UNIV_SYNC_DEBUG */
203 204
	UT_LIST_REMOVE(view_list, trx_sys->view_list, view);
} 
monty@donna.mysql.fi's avatar
Merge  
monty@donna.mysql.fi committed
205

heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
/*************************************************************************
Closes a consistent read view for MySQL. This function is called at an SQL
statement end if the trx isolation level is <= TRX_ISO_READ_COMMITTED. */

void
read_view_close_for_mysql(
/*======================*/
	trx_t*	trx)	/* in: trx which has a read view */
{
	ut_a(trx->read_view);

	mutex_enter(&kernel_mutex);

	read_view_close(trx->read_view);

	mem_heap_empty(trx->read_view_heap);

	trx->read_view = NULL;

	mutex_exit(&kernel_mutex);
}
	
monty@donna.mysql.fi's avatar
Merge  
monty@donna.mysql.fi committed
228 229 230 231 232 233 234 235 236 237 238 239
/*************************************************************************
Prints a read view to stderr. */

void
read_view_print(
/*============*/
	read_view_t*	view)	/* in: read view */
{
	ulint	n_ids;
	ulint	i;
	
	fprintf(stderr, "Read view low limit trx n:o %lu %lu\n",
240 241
			(ulong) ut_dulint_get_high(view->low_limit_no),
			(ulong) ut_dulint_get_low(view->low_limit_no));
monty@donna.mysql.fi's avatar
Merge  
monty@donna.mysql.fi committed
242 243

	fprintf(stderr, "Read view up limit trx id %lu %lu\n",
244 245
			(ulong) ut_dulint_get_high(view->up_limit_id),
			(ulong) ut_dulint_get_low(view->up_limit_id));		
monty@donna.mysql.fi's avatar
Merge  
monty@donna.mysql.fi committed
246 247

	fprintf(stderr, "Read view low limit trx id %lu %lu\n",
248 249
			(ulong) ut_dulint_get_high(view->low_limit_id),
			(ulong) ut_dulint_get_low(view->low_limit_id));
monty@donna.mysql.fi's avatar
Merge  
monty@donna.mysql.fi committed
250 251 252 253 254 255 256

	fprintf(stderr, "Read view individually stored trx ids:\n");

	n_ids = view->n_trx_ids;

	for (i = 0; i < n_ids; i++) {
		fprintf(stderr, "Read view trx id %lu %lu\n",
257 258
			(ulong) ut_dulint_get_high(read_view_get_nth_trx_id(view, i)),
			(ulong) ut_dulint_get_low(read_view_get_nth_trx_id(view, i)));
monty@donna.mysql.fi's avatar
Merge  
monty@donna.mysql.fi committed
259 260
	}
}