Commit ec55fec9 authored by unknown's avatar unknown

Implement MySQL framework to support consistent read views in

cursors. This should fix Bug#11813 when InnoDB part is in 
(tested with a draft patch).
The idea of the patch is that if a storage engine supports
consistent read views, we open one when open a cursor,
set is as the active view when fetch from the cursor, and close
together with cursor close.


sql/examples/ha_archive.cc:
  - extend handlerton with cursors methods; fix coding style
sql/examples/ha_example.cc:
  - extend handlerton with cursors methods; fix coding style
sql/examples/ha_tina.cc:
  - extend handlerton with cursors methods; fix coding style
sql/ha_berkeley.cc:
  - extend handlerton with cursors methods
sql/ha_blackhole.cc:
  - extend handlerton with cursors methods; fix coding style
sql/ha_federated.cc:
  - extend handlerton with cursors methods; fix coding style
sql/ha_heap.cc:
  - extend handlerton with cursors methods; fix coding style
sql/ha_innodb.cc:
  - extend handlerton with cursors methods
sql/ha_myisam.cc:
  - extend handlerton with cursors methods; fix coding style
sql/ha_myisammrg.cc:
  - extend handlerton with cursors methods; fix coding style
sql/ha_ndbcluster.cc:
  - extend handlerton with cursors methods
sql/handler.h:
  - extend handlerton with cursors methods
sql/sql_select.cc:
  - create a consistent read view when we open a cursor,
    set it for a fetch, and free when we closing the cursor.
sql/sql_select.h:
  - add Cursor::ht_info to remember read views used in a cursor.
tests/mysql_client_test.c:
  Disable an assert that will be no longer valid when consistent
  read views in InnoDB are used.
parent b6823b66
......@@ -140,16 +140,19 @@ static handlerton archive_hton = {
"archive",
0, /* slot */
0, /* savepoint size. */
0, /* close_connection */
0, /* savepoint */
0, /* rollback to savepoint */
0, /* releas savepoint */
0, /* commit */
0, /* rollback */
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
0, /* rollback_by_xid */
NULL, /* close_connection */
NULL, /* savepoint */
NULL, /* rollback to savepoint */
NULL, /* releas savepoint */
NULL, /* commit */
NULL, /* rollback */
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS
};
......
......@@ -77,16 +77,19 @@ static handlerton example_hton= {
"CSV",
0, /* slot */
0, /* savepoint size. */
0, /* close_connection */
0, /* savepoint */
0, /* rollback to savepoint */
0, /* release savepoint */
0, /* commit */
0, /* rollback */
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
0, /* rollback_by_xid */
NULL, /* close_connection */
NULL, /* savepoint */
NULL, /* rollback to savepoint */
NULL, /* release savepoint */
NULL, /* commit */
NULL, /* rollback */
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS
};
......
......@@ -58,16 +58,19 @@ static handlerton tina_hton= {
"CSV",
0, /* slot */
0, /* savepoint size. */
0, /* close_connection */
0, /* savepoint */
0, /* rollback to savepoint */
0, /* release savepoint */
0, /* commit */
0, /* rollback */
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
0, /* rollback_by_xid */
NULL, /* close_connection */
NULL, /* savepoint */
NULL, /* rollback to savepoint */
NULL, /* release savepoint */
NULL, /* commit */
NULL, /* rollback */
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS
};
......
......@@ -121,6 +121,9 @@ static handlerton berkeley_hton = {
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_CLOSE_CURSORS_AT_COMMIT
};
......
......@@ -30,16 +30,19 @@ static handlerton blackhole_hton= {
"BLACKHOLE",
0, /* slot */
0, /* savepoint size. */
0, /* close_connection */
0, /* savepoint */
0, /* rollback to savepoint */
0, /* release savepoint */
0, /* commit */
0, /* rollback */
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
0, /* rollback_by_xid */
NULL, /* close_connection */
NULL, /* savepoint */
NULL, /* rollback to savepoint */
NULL, /* release savepoint */
NULL, /* commit */
NULL, /* rollback */
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS
};
......
......@@ -685,16 +685,19 @@ static handlerton federated_hton= {
"FEDERATED",
0, /* slot */
0, /* savepoint size. */
0, /* close_connection */
0, /* savepoint */
0, /* rollback to savepoint */
0, /* release savepoint */
0, /* commit */
0, /* rollback */
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
0, /* rollback_by_xid */
NULL, /* close_connection */
NULL, /* savepoint */
NULL, /* rollback to savepoint */
NULL, /* release savepoint */
NULL, /* commit */
NULL, /* rollback */
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS
};
......
......@@ -27,16 +27,19 @@ static handlerton heap_hton= {
"MEMORY",
0, /* slot */
0, /* savepoint size. */
0, /* close_connection */
0, /* savepoint */
0, /* rollback to savepoint */
0, /* release savepoint */
0, /* commit */
0, /* rollback */
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
0, /* rollback_by_xid */
NULL, /* close_connection */
NULL, /* savepoint */
NULL, /* rollback to savepoint */
NULL, /* release savepoint */
NULL, /* commit */
NULL, /* rollback */
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS
};
......
......@@ -216,12 +216,9 @@ static handlerton innobase_hton = {
innobase_xa_recover, /* recover */
innobase_commit_by_xid, /* commit_by_xid */
innobase_rollback_by_xid, /* rollback_by_xid */
/*
For now when one opens a cursor, MySQL does not create an own
InnoDB consistent read view for it, and uses the view of the
currently active transaction. Therefore, cursors can not
survive COMMIT or ROLLBACK statements, which free this view.
*/
NULL,
NULL,
NULL,
HTON_CLOSE_CURSORS_AT_COMMIT
};
......
......@@ -50,16 +50,19 @@ static handlerton myisam_hton= {
"MyISAM",
0, /* slot */
0, /* savepoint size. */
0, /* close_connection */
0, /* savepoint */
0, /* rollback to savepoint */
0, /* release savepoint */
0, /* commit */
0, /* rollback */
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
0, /* rollback_by_xid */
NULL, /* close_connection */
NULL, /* savepoint */
NULL, /* rollback to savepoint */
NULL, /* release savepoint */
NULL, /* commit */
NULL, /* rollback */
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
/*
MyISAM doesn't support transactions and doesn't have
transaction-dependent context: cursors can survive a commit.
......
......@@ -38,16 +38,19 @@ static handlerton myisammrg_hton= {
"MRG_MyISAM",
0, /* slot */
0, /* savepoint size. */
0, /* close_connection */
0, /* savepoint */
0, /* rollback to savepoint */
0, /* release savepoint */
0, /* commit */
0, /* rollback */
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
0, /* rollback_by_xid */
NULL, /* close_connection */
NULL, /* savepoint */
NULL, /* rollback to savepoint */
NULL, /* release savepoint */
NULL, /* commit */
NULL, /* rollback */
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS
};
......
......@@ -63,6 +63,9 @@ static handlerton ndbcluster_hton = {
NULL, /* recover */
NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS
};
......
......@@ -106,9 +106,11 @@
/*
Note: the following includes binlog and closing 0.
so: innodb+bdb+ndb+binlog+0
so: innodb + bdb + ndb + binlog + myisam + myisammrg + archive +
example + csv + heap + blackhole + federated + 0
(yes, the sum is deliberately inaccurate)
*/
#define MAX_HA 6
#define MAX_HA 14
/*
Bits in index_ddl_flags(KEY *wanted_index)
......@@ -349,6 +351,9 @@ typedef struct
int (*recover)(XID *xid_list, uint len);
int (*commit_by_xid)(XID *xid);
int (*rollback_by_xid)(XID *xid);
void *(*create_cursor_read_view)();
void (*set_cursor_read_view)(void *);
void (*close_cursor_read_view)(void *);
uint32 flags; /* global handler flags */
} handlerton;
......
......@@ -1712,12 +1712,14 @@ Cursor::Cursor(THD *thd)
/* We will overwrite it at open anyway. */
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
thr_lock_owner_init(&lock_id, &thd->lock_info);
bzero((void*) ht_info, sizeof(ht_info));
}
void
Cursor::init_from_thd(THD *thd)
{
Engine_info *info;
/*
We need to save and reset thd->mem_root, otherwise it'll be freed
later in mysql_parse.
......@@ -1749,15 +1751,16 @@ Cursor::init_from_thd(THD *thd)
thd->lock_info.n_cursors++;
close_at_commit= FALSE; /* reset in case we're reusing the cursor */
for (TABLE *table= open_tables; table; table= table->next)
info= &ht_info[0];
for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
{
const handlerton *ht= table->file->ht;
if (ht)
const handlerton *ht= *pht;
close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
else
if (ht->create_cursor_read_view)
{
close_at_commit= TRUE; /* handler status is unknown */
break;
info->ht= ht;
info->read_view= (ht->create_cursor_read_view)();
++info;
}
}
/*
......@@ -1853,6 +1856,9 @@ Cursor::fetch(ulong num_rows)
/* save references to memory, allocated during fetch */
thd->set_n_backup_item_arena(this, &backup_arena);
for (Engine_info *info= ht_info; info->read_view ; info++)
(info->ht->set_cursor_read_view)(info->read_view);
join->fetch_limit+= num_rows;
error= sub_select(join, join_tab, 0);
......@@ -1869,6 +1875,9 @@ Cursor::fetch(ulong num_rows)
/* Grab free_list here to correctly free it in close */
thd->restore_backup_item_arena(this, &backup_arena);
for (Engine_info *info= ht_info; info->read_view; info++)
(info->ht->set_cursor_read_view)(0);
if (error == NESTED_LOOP_CURSOR_LIMIT)
{
/* Fetch limit worked, possibly more rows are there */
......@@ -1909,6 +1918,13 @@ Cursor::close(bool is_active)
else
(void) join->select_lex->cleanup();
for (Engine_info *info= ht_info; info->read_view; info++)
{
(info->ht->close_cursor_read_view)(info->read_view);
info->read_view= 0;
info->ht= 0;
}
if (is_active)
close_thread_tables(thd);
else
......
......@@ -389,6 +389,12 @@ class Cursor: public Sql_alloc, public Query_arena
TABLE *derived_tables;
/* List of items created during execution */
query_id_t query_id;
struct Engine_info
{
const handlerton *ht;
void *read_view;
};
Engine_info ht_info[MAX_HA];
public:
Item_change_list change_list;
select_send result;
......
......@@ -13874,10 +13874,12 @@ static void test_bug10760()
printf("Fetched row %s\n", id_buf);
rc= mysql_rollback(mysql); /* should close the cursor */
myquery(rc);
#if 0
rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(rc);
if (!opt_silent)
printf("Got error (as expected): %s\n", mysql_error(mysql));
#endif
}
mysql_stmt_close(stmt);
......
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