2001-02-17 13:19:19 +01:00
|
|
|
/******************************************************
|
|
|
|
Mini-transaction buffer
|
|
|
|
|
|
|
|
(c) 1995 Innobase Oy
|
|
|
|
|
|
|
|
Created 11/26/1995 Heikki Tuuri
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#include "mtr0mtr.h"
|
|
|
|
|
|
|
|
#ifdef UNIV_NONINL
|
|
|
|
#include "mtr0mtr.ic"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "buf0buf.h"
|
|
|
|
#include "page0types.h"
|
|
|
|
#include "mtr0log.h"
|
|
|
|
#include "log0log.h"
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
Starts a mini-transaction and creates a mini-transaction handle
|
|
|
|
and buffer in the memory buffer given by the caller. */
|
|
|
|
|
|
|
|
mtr_t*
|
|
|
|
mtr_start_noninline(
|
|
|
|
/*================*/
|
|
|
|
/* out: mtr buffer which also acts as
|
|
|
|
the mtr handle */
|
|
|
|
mtr_t* mtr) /* in: memory buffer for the mtr buffer */
|
|
|
|
{
|
|
|
|
return(mtr_start(mtr));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
Releases the item in the slot given. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
mtr_memo_slot_release(
|
|
|
|
/*==================*/
|
|
|
|
mtr_t* mtr, /* in: mtr */
|
|
|
|
mtr_memo_slot_t* slot) /* in: memo slot */
|
|
|
|
{
|
|
|
|
void* object;
|
|
|
|
ulint type;
|
|
|
|
|
|
|
|
ut_ad(mtr && slot);
|
|
|
|
|
|
|
|
object = slot->object;
|
|
|
|
type = slot->type;
|
|
|
|
|
|
|
|
if (object != NULL) {
|
|
|
|
if (type <= MTR_MEMO_BUF_FIX) {
|
|
|
|
buf_page_release((buf_block_t*)object, type, mtr);
|
|
|
|
} else if (type == MTR_MEMO_S_LOCK) {
|
|
|
|
rw_lock_s_unlock((rw_lock_t*)object);
|
|
|
|
#ifndef UNIV_DEBUG
|
|
|
|
} else {
|
|
|
|
rw_lock_x_unlock((rw_lock_t*)object);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
} else if (type == MTR_MEMO_X_LOCK) {
|
|
|
|
rw_lock_x_unlock((rw_lock_t*)object);
|
|
|
|
} else {
|
|
|
|
ut_ad(type == MTR_MEMO_MODIFY);
|
|
|
|
ut_ad(mtr_memo_contains(mtr, object,
|
|
|
|
MTR_MEMO_PAGE_X_FIX));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
slot->object = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************
|
|
|
|
Releases the mlocks and other objects stored in an mtr memo. They are released
|
|
|
|
in the order opposite to which they were pushed to the memo. NOTE! It is
|
|
|
|
essential that the x-rw-lock on a modified buffer page is not released before
|
|
|
|
buf_page_note_modification is called for that page! Otherwise, some thread
|
|
|
|
might race to modify it, and the flush list sort order on lsn would be
|
|
|
|
destroyed. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
mtr_memo_pop_all(
|
|
|
|
/*=============*/
|
|
|
|
mtr_t* mtr) /* in: mtr */
|
|
|
|
{
|
|
|
|
mtr_memo_slot_t* slot;
|
|
|
|
dyn_array_t* memo;
|
|
|
|
ulint offset;
|
|
|
|
|
|
|
|
ut_ad(mtr);
|
|
|
|
ut_ad(mtr->magic_n == MTR_MAGIC_N);
|
|
|
|
ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
|
|
|
|
commit */
|
|
|
|
memo = &(mtr->memo);
|
|
|
|
|
|
|
|
offset = dyn_array_get_data_size(memo);
|
|
|
|
|
|
|
|
while (offset > 0) {
|
|
|
|
offset -= sizeof(mtr_memo_slot_t);
|
|
|
|
slot = dyn_array_get_element(memo, offset);
|
|
|
|
|
|
|
|
mtr_memo_slot_release(mtr, slot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
Writes the contents of a mini-transaction log, if any, to the database log. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
mtr_log_reserve_and_write(
|
|
|
|
/*======================*/
|
|
|
|
mtr_t* mtr) /* in: mtr */
|
|
|
|
{
|
|
|
|
dyn_array_t* mlog;
|
|
|
|
dyn_block_t* block;
|
|
|
|
ulint data_size;
|
|
|
|
ibool success;
|
|
|
|
byte* first_data;
|
|
|
|
|
|
|
|
ut_ad(mtr);
|
|
|
|
|
|
|
|
mlog = &(mtr->log);
|
|
|
|
|
|
|
|
first_data = dyn_block_get_data(mlog);
|
|
|
|
|
|
|
|
if (mtr->n_log_recs > 1) {
|
|
|
|
mlog_catenate_ulint(mtr, MLOG_MULTI_REC_END, MLOG_1BYTE);
|
|
|
|
} else {
|
|
|
|
*first_data = (byte)((ulint)*first_data | MLOG_SINGLE_REC_FLAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mlog->heap == NULL) {
|
|
|
|
mtr->end_lsn = log_reserve_and_write_fast(first_data,
|
|
|
|
dyn_block_get_used(mlog),
|
|
|
|
&(mtr->start_lsn), &success);
|
|
|
|
if (success) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data_size = dyn_array_get_data_size(mlog);
|
2002-06-22 19:41:14 +02:00
|
|
|
|
2001-02-17 13:19:19 +01:00
|
|
|
/* Open the database log for log_write_low */
|
|
|
|
mtr->start_lsn = log_reserve_and_open(data_size);
|
|
|
|
|
|
|
|
if (mtr->log_mode == MTR_LOG_ALL) {
|
|
|
|
|
2004-05-26 09:45:37 +02:00
|
|
|
block = mlog;
|
2001-02-17 13:19:19 +01:00
|
|
|
|
2004-05-26 09:45:37 +02:00
|
|
|
while (block != NULL) {
|
|
|
|
log_write_low(dyn_block_get_data(block),
|
|
|
|
dyn_block_get_used(block));
|
|
|
|
block = dyn_array_get_next_block(mlog, block);
|
2001-02-17 13:19:19 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ut_ad(mtr->log_mode == MTR_LOG_NONE);
|
|
|
|
/* Do nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
mtr->end_lsn = log_close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
Commits a mini-transaction. */
|
|
|
|
|
|
|
|
void
|
|
|
|
mtr_commit(
|
|
|
|
/*=======*/
|
|
|
|
mtr_t* mtr) /* in: mini-transaction */
|
|
|
|
{
|
|
|
|
ut_ad(mtr);
|
|
|
|
ut_ad(mtr->magic_n == MTR_MAGIC_N);
|
|
|
|
ut_ad(mtr->state == MTR_ACTIVE);
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
mtr->state = MTR_COMMITTING;
|
|
|
|
#endif
|
|
|
|
if (mtr->modifications) {
|
|
|
|
mtr_log_reserve_and_write(mtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We first update the modification info to buffer pages, and only
|
|
|
|
after that release the log mutex: this guarantees that when the log
|
|
|
|
mutex is free, all buffer pages contain an up-to-date info of their
|
|
|
|
modifications. This fact is used in making a checkpoint when we look
|
|
|
|
at the oldest modification of any page in the buffer pool. It is also
|
|
|
|
required when we insert modified buffer pages in to the flush list
|
|
|
|
which must be sorted on oldest_modification. */
|
|
|
|
|
|
|
|
mtr_memo_pop_all(mtr);
|
|
|
|
|
|
|
|
if (mtr->modifications) {
|
|
|
|
log_release();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
mtr->state = MTR_COMMITTED;
|
|
|
|
#endif
|
|
|
|
dyn_array_free(&(mtr->memo));
|
|
|
|
dyn_array_free(&(mtr->log));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************
|
|
|
|
Releases the latches stored in an mtr memo down to a savepoint.
|
|
|
|
NOTE! The mtr must not have made changes to buffer pages after the
|
|
|
|
savepoint, as these can be handled only by mtr_commit. */
|
|
|
|
|
|
|
|
void
|
|
|
|
mtr_rollback_to_savepoint(
|
|
|
|
/*======================*/
|
|
|
|
mtr_t* mtr, /* in: mtr */
|
|
|
|
ulint savepoint) /* in: savepoint */
|
|
|
|
{
|
|
|
|
mtr_memo_slot_t* slot;
|
|
|
|
dyn_array_t* memo;
|
|
|
|
ulint offset;
|
|
|
|
|
|
|
|
ut_ad(mtr);
|
|
|
|
ut_ad(mtr->magic_n == MTR_MAGIC_N);
|
|
|
|
ut_ad(mtr->state == MTR_ACTIVE);
|
|
|
|
|
|
|
|
memo = &(mtr->memo);
|
|
|
|
|
|
|
|
offset = dyn_array_get_data_size(memo);
|
|
|
|
ut_ad(offset >= savepoint);
|
|
|
|
|
|
|
|
while (offset > savepoint) {
|
|
|
|
offset -= sizeof(mtr_memo_slot_t);
|
|
|
|
|
|
|
|
slot = dyn_array_get_element(memo, offset);
|
|
|
|
|
|
|
|
ut_ad(slot->type != MTR_MEMO_MODIFY);
|
|
|
|
mtr_memo_slot_release(mtr, slot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************
|
|
|
|
Releases an object in the memo stack. */
|
|
|
|
|
|
|
|
void
|
|
|
|
mtr_memo_release(
|
|
|
|
/*=============*/
|
|
|
|
mtr_t* mtr, /* in: mtr */
|
|
|
|
void* object, /* in: object */
|
|
|
|
ulint type) /* in: object type: MTR_MEMO_S_LOCK, ... */
|
|
|
|
{
|
|
|
|
mtr_memo_slot_t* slot;
|
|
|
|
dyn_array_t* memo;
|
|
|
|
ulint offset;
|
|
|
|
|
|
|
|
ut_ad(mtr);
|
|
|
|
ut_ad(mtr->magic_n == MTR_MAGIC_N);
|
|
|
|
ut_ad(mtr->state == MTR_ACTIVE);
|
|
|
|
|
|
|
|
memo = &(mtr->memo);
|
|
|
|
|
|
|
|
offset = dyn_array_get_data_size(memo);
|
|
|
|
|
|
|
|
while (offset > 0) {
|
|
|
|
offset -= sizeof(mtr_memo_slot_t);
|
|
|
|
|
|
|
|
slot = dyn_array_get_element(memo, offset);
|
|
|
|
|
|
|
|
if ((object == slot->object) && (type == slot->type)) {
|
|
|
|
|
|
|
|
mtr_memo_slot_release(mtr, slot);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
Reads 1 - 4 bytes from a file page buffered in the buffer pool. */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
mtr_read_ulint(
|
|
|
|
/*===========*/
|
|
|
|
/* out: value read */
|
|
|
|
byte* ptr, /* in: pointer from where to read */
|
|
|
|
ulint type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
|
2001-11-05 22:48:03 +01:00
|
|
|
mtr_t* mtr __attribute__((unused)))
|
|
|
|
/* in: mini-transaction handle */
|
2001-02-17 13:19:19 +01:00
|
|
|
{
|
|
|
|
ut_ad(mtr->state == MTR_ACTIVE);
|
|
|
|
ut_ad(mtr_memo_contains(mtr, buf_block_align(ptr),
|
|
|
|
MTR_MEMO_PAGE_S_FIX) ||
|
|
|
|
mtr_memo_contains(mtr, buf_block_align(ptr),
|
|
|
|
MTR_MEMO_PAGE_X_FIX));
|
|
|
|
if (type == MLOG_1BYTE) {
|
|
|
|
return(mach_read_from_1(ptr));
|
|
|
|
} else if (type == MLOG_2BYTES) {
|
|
|
|
return(mach_read_from_2(ptr));
|
|
|
|
} else {
|
|
|
|
ut_ad(type == MLOG_4BYTES);
|
|
|
|
return(mach_read_from_4(ptr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
Reads 8 bytes from a file page buffered in the buffer pool. */
|
|
|
|
|
|
|
|
dulint
|
|
|
|
mtr_read_dulint(
|
|
|
|
/*===========*/
|
|
|
|
/* out: value read */
|
|
|
|
byte* ptr, /* in: pointer from where to read */
|
2001-11-05 22:48:03 +01:00
|
|
|
mtr_t* mtr __attribute__((unused)))
|
|
|
|
/* in: mini-transaction handle */
|
2001-02-17 13:19:19 +01:00
|
|
|
{
|
|
|
|
ut_ad(mtr->state == MTR_ACTIVE);
|
|
|
|
ut_ad(ptr && mtr);
|
|
|
|
ut_ad(mtr_memo_contains(mtr, buf_block_align(ptr),
|
|
|
|
MTR_MEMO_PAGE_S_FIX) ||
|
|
|
|
mtr_memo_contains(mtr, buf_block_align(ptr),
|
|
|
|
MTR_MEMO_PAGE_X_FIX));
|
|
|
|
return(mach_read_from_8(ptr));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************
|
|
|
|
Prints info of an mtr handle. */
|
|
|
|
|
|
|
|
void
|
|
|
|
mtr_print(
|
|
|
|
/*======*/
|
|
|
|
mtr_t* mtr) /* in: mtr */
|
|
|
|
{
|
InnoDB: send diagnostic output to stderr or files
instead of stdout or fixed-size memory buffers
innobase/btr/btr0btr.c:
Output to stderr; quote table and index names
innobase/btr/btr0cur.c:
Output to stderr; quote table and index names
innobase/btr/btr0sea.c:
Output to stderr
innobase/buf/buf0buf.c:
Output to stderr; quote table and index names
innobase/buf/buf0flu.c:
Output to stderr
innobase/buf/buf0lru.c:
Output to stderr
innobase/buf/buf0rea.c:
Output to stderr
innobase/data/data0data.c:
Remove dtuple_validate() unless #ifdef UNIV_DEBUG
Remove unnecessary sprintf() calls
Output to stderr
innobase/data/data0type.c:
Output to stderr
innobase/dict/dict0boot.c:
Remove dummy call to printf()
innobase/dict/dict0crea.c:
Output diagnostic information to stream, not to memory
innobase/dict/dict0dict.c:
Output diagnostics to a file, not to a memory buffer
innobase/dict/dict0load.c:
Output to stderr; quote table and index names
innobase/eval/eval0eval.c:
Output to stderr
innobase/fil/fil0fil.c:
Output to stderr
innobase/fsp/fsp0fsp.c:
Output to stderr
Avoid sprintf()
innobase/fut/fut0lst.c:
Output to stderr
innobase/ha/ha0ha.c:
Output to stream, not to memory buffer
innobase/ibuf/ibuf0ibuf.c:
Output to stderr
Avoid sprintf()
innobase/include/buf0buf.h:
Output to stream, not to memory buffer
innobase/include/buf0buf.ic:
Use %p for displaying pointers
innobase/include/data0data.h:
Remove dtuple_sprintf()
innobase/include/dict0dict.h:
Output to stream, not to memory buffer
innobase/include/ha0ha.h:
Output to stream, not to memory buffer
innobase/include/ibuf0ibuf.h:
Output to stream, not to memory buffer
innobase/include/lock0lock.h:
Output to stream, not to memory buffer
innobase/include/log0log.h:
Output to stream, not to memory buffer
innobase/include/mtr0log.ic:
Output to stderr
Display pointers with %p
innobase/include/os0file.h:
Output to stream, not to memory buffer
innobase/include/rem0rec.h:
Remove rec_sprintf()
innobase/include/rem0rec.ic:
Output to stderr
innobase/include/row0sel.ic:
Output to stderr
innobase/include/row0upd.ic:
Quote table and index names
innobase/include/srv0srv.h:
Remove srv_sprintf_innodb_monitor()
innobase/include/sync0arr.h:
Output to stream, not to memory buffer
innobase/include/sync0sync.h:
Output to stream, not to memory buffer
innobase/include/trx0sys.h:
Output to stderr
innobase/include/trx0trx.h:
Output to stream, not to memory buffer
innobase/include/ut0ut.h:
Remove ut_sprintf_buf()
Add ut_print_name(), ut_print_namel() and ut_copy_file()
innobase/lock/lock0lock.c:
Output to stream, not to memory buffer
innobase/log/log0log.c:
Output to stderr
innobase/log/log0recv.c:
Output to stderr
innobase/mem/mem0dbg.c:
Output to stderr
innobase/mtr/mtr0log.c:
Display pointers with %p
innobase/mtr/mtr0mtr.c:
Output to stderr
innobase/os/os0file.c:
Output to stream, not to memory buffer
innobase/os/os0proc.c:
Output to stderr
innobase/os/os0thread.c:
Output to stderr
innobase/page/page0cur.c:
Output to stderr
innobase/page/page0page.c:
Avoid sprintf()
Output to stderr instead of stdout
innobase/pars/pars0opt.c:
Output to stderr instead of stdout
innobase/rem/rem0rec.c:
Remove rec_sprintf()
Output to stderr instead of stdout
innobase/row/row0ins.c:
Output diagnostics to stream instead of memory buffer
innobase/row/row0mysql.c:
Output to stderr instead of stdout
Quote table and index names
innobase/row/row0purge.c:
Output to stderr instead of stdout
innobase/row/row0row.c:
Quote table and index names
innobase/row/row0sel.c:
Output to stderr instead of stdout
Quote table and index names
innobase/row/row0umod.c:
Avoid sprintf()
Quote table and index names
innobase/row/row0undo.c:
Output to stderr instead of stdout
innobase/row/row0upd.c:
Avoid sprintf()
innobase/srv/srv0srv.c:
Output to stderr instead of stdout
innobase/srv/srv0start.c:
Handle srv_monitor_file
Make some global variables static
innobase/sync/sync0arr.c:
Output to stderr instead of stdout
Output to stream instead of memory buffer
innobase/sync/sync0rw.c:
Output to stderr instead of stdout
innobase/sync/sync0sync.c:
Output to stderr instead of stdout
Output to stream instead of memory buffer
innobase/trx/trx0purge.c:
Output to stderr instead of stdout
innobase/trx/trx0rec.c:
Quote index and table names
Avoid sprintf()
innobase/trx/trx0roll.c:
Quote identifier names
Output to stderr instead of stdout
innobase/trx/trx0sys.c:
Output to stderr instead of stdout
innobase/trx/trx0trx.c:
Output to stream instead of memory buffer
innobase/trx/trx0undo.c:
Output to stderr instead of stdout
innobase/ut/ut0ut.c:
Declare mysql_get_identifier_quote_char()
Remove ut_sprintf_buf()
Add ut_print_name() and ut_print_namel()
Add ut_copy_file()
sql/ha_innodb.cc:
innobase_mysql_print_thd(): output to stream, not to memory buffer
Add mysql_get_identifier_quote_char()
Remove unused function innobase_print_error()
Display pointers with %p
Buffer InnoDB output via files, not via statically allocated memory
2004-04-06 15:14:43 +02:00
|
|
|
fprintf(stderr,
|
2001-02-17 13:19:19 +01:00
|
|
|
"Mini-transaction handle: memo size %lu bytes log size %lu bytes\n",
|
2003-12-20 02:41:04 +01:00
|
|
|
(ulong) dyn_array_get_data_size(&(mtr->memo)),
|
|
|
|
(ulong) dyn_array_get_data_size(&(mtr->log)));
|
2001-02-17 13:19:19 +01:00
|
|
|
}
|