Skip to content

Commit 5f78be6

Browse files
author
Allen.Lai
committed
Bug#20390277 MEMCACHE: FLUSH_ALL: TABLE->MEMCACHED_SYNC_COUNT >= 0
We need to block all dmls from both SQL layer and memcached when flush_all is running. Reviewed-by: Jimmy Yang<[email protected]> RB: 7804
1 parent fc3adce commit 5f78be6

5 files changed

Lines changed: 110 additions & 36 deletions

File tree

plugin/innodb_memcached/innodb_memcache/include/handler_api.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
3+
Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
44
55
This program is free software; you can redistribute it and/or modify it under
66
the terms of the GNU General Public License as published by the Free Software
@@ -32,6 +32,7 @@ Created 3/14/2011 Jimmy Yang
3232
/** Defines for handler_unlock_table()'s mode field */
3333
#define HDL_READ 0x1
3434
#define HDL_WRITE 0x2
35+
#define HDL_FLUSH 0x3
3536

3637
/** Defines for handler_binlog_row()'s mode field */
3738
typedef enum hdl_op_type {

plugin/innodb_memcached/innodb_memcache/include/innodb_engine.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/***********************************************************************
22
3-
Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
3+
Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
44
55
This program is free software; you can redistribute it and/or modify it
66
under the terms of the GNU General Public License as published by the
@@ -74,6 +74,7 @@ struct innodb_conn_data_struct {
7474
is processing a request */
7575
bool is_stale; /*!< connection closed, this is
7676
stale */
77+
bool is_flushing; /*!< if flush is running. */
7778
void* conn_cookie; /*!< connection cookie */
7879
uint64_t n_total_reads; /*!< number of reads */
7980
uint64_t n_reads_since_commit;
@@ -147,6 +148,8 @@ typedef struct innodb_engine {
147148
connection specific data */
148149
pthread_mutex_t cas_mutex; /*!< mutex synchronizes
149150
CAS */
151+
pthread_mutex_t flush_mutex; /*!< mutex synchronizes
152+
flush and DMLs. */
150153
pthread_t bk_thd_for_commit;/*!< background thread for
151154
committing long running
152155
transactions */

plugin/innodb_memcached/innodb_memcache/src/handler_api.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
3+
Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
44
55
This program is free software; you can redistribute it and/or modify it under
66
the terms of the GNU General Public License as published by the Free Software
@@ -151,6 +151,17 @@ handler_open_table(
151151
? MDL_SHARED_WRITE
152152
: MDL_SHARED_READ, MDL_TRANSACTION);
153153

154+
/* For flush, we need to request exclusive mdl lock. */
155+
if (lock_type == HDL_FLUSH) {
156+
tables.mdl_request.init(MDL_key::TABLE, db_name, table_name,
157+
MDL_EXCLUSIVE, MDL_TRANSACTION);
158+
} else {
159+
tables.mdl_request.init(MDL_key::TABLE, db_name, table_name,
160+
(lock_mode > TL_READ)
161+
? MDL_SHARED_WRITE
162+
: MDL_SHARED_READ, MDL_TRANSACTION);
163+
}
164+
154165
if (!open_table(thd, &tables, &table_ctx)) {
155166
TABLE* table = tables.table;
156167
table->use_all_columns();

plugin/innodb_memcached/innodb_memcache/src/innodb_api.c

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,40 @@ innodb_api_begin(
170170
return(err);
171171
}
172172

173+
/* If MDL is enabled, we need to create mysql handler. */
174+
if (engine) {
175+
/* Create a "Fake" THD if binlog is enabled */
176+
/* For flush_all which request IB_LOCK_TABLE_X
177+
lock, we need to add MDL lock. It's because we need
178+
to block DMLs from sql layer. */
179+
if (conn_data && (engine->enable_binlog
180+
|| engine->enable_mdl
181+
|| lock_mode == IB_LOCK_TABLE_X)) {
182+
if (!conn_data->thd) {
183+
conn_data->thd = handler_create_thd(
184+
engine->enable_binlog);
185+
186+
if (!conn_data->thd) {
187+
innodb_cb_cursor_close(*crsr);
188+
*crsr = NULL;
189+
return(DB_ERROR);
190+
}
191+
}
192+
193+
if (!conn_data->mysql_tbl) {
194+
int lock_type =
195+
(lock_mode == IB_LOCK_TABLE_X?
196+
HDL_FLUSH : HDL_WRITE);
197+
conn_data->mysql_tbl =
198+
handler_open_table(
199+
conn_data->thd,
200+
dbname,
201+
name,
202+
lock_type);
203+
}
204+
}
205+
}
206+
173207
err = innodb_cb_cursor_lock(engine, *crsr, lock_mode);
174208

175209
if (err != DB_SUCCESS) {
@@ -208,30 +242,8 @@ innodb_api_begin(
208242
err = innodb_cb_cursor_lock(engine, *idx_crsr,
209243
lock_mode);
210244
}
211-
212-
/* Create a "Fake" THD if binlog is enabled */
213-
if (conn_data && (engine->enable_binlog
214-
|| engine->enable_mdl)) {
215-
if (!conn_data->thd) {
216-
conn_data->thd = handler_create_thd(
217-
engine->enable_binlog);
218-
219-
if (!conn_data->thd) {
220-
innodb_cb_cursor_close(*crsr);
221-
*crsr = NULL;
222-
return(DB_ERROR);
223-
}
224-
}
225-
226-
if (!conn_data->mysql_tbl) {
227-
conn_data->mysql_tbl =
228-
handler_open_table(
229-
conn_data->thd,
230-
dbname,
231-
name, HDL_WRITE);
232-
}
233-
}
234245
}
246+
235247
} else {
236248
ib_cb_cursor_new_trx(*crsr, ib_trx);
237249

plugin/innodb_memcached/innodb_memcache/src/innodb_engine.c

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ innodb_initialize(
424424
UT_LIST_INIT(innodb_eng->conn_data);
425425
pthread_mutex_init(&innodb_eng->conn_mutex, NULL);
426426
pthread_mutex_init(&innodb_eng->cas_mutex, NULL);
427+
pthread_mutex_init(&innodb_eng->flush_mutex, NULL);
427428

428429
/* Fetch InnoDB specific settings */
429430
innodb_eng->meta_info = innodb_config(
@@ -684,6 +685,7 @@ innodb_destroy(
684685

685686
pthread_mutex_destroy(&innodb_eng->conn_mutex);
686687
pthread_mutex_destroy(&innodb_eng->cas_mutex);
688+
pthread_mutex_destroy(&innodb_eng->flush_mutex);
687689

688690
if (innodb_eng->default_engine) {
689691
def_eng->engine.destroy(innodb_eng->default_engine, force);
@@ -771,6 +773,8 @@ innodb_conn_init(
771773
conn_data->cmd_buf = malloc(1024);
772774
conn_data->cmd_buf_len = 1024;
773775

776+
conn_data->is_flushing = false;
777+
774778
pthread_mutex_init(&conn_data->curr_conn_mutex, NULL);
775779
UNLOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
776780
}
@@ -785,6 +789,15 @@ innodb_conn_init(
785789
}
786790

787791
LOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
792+
793+
/* If flush is running, then wait for it complete. */
794+
if (conn_data->is_flushing) {
795+
/* Request flush_mutex for waiting for flush
796+
completed. */
797+
pthread_mutex_lock(&engine->flush_mutex);
798+
pthread_mutex_unlock(&engine->flush_mutex);
799+
}
800+
788801
conn_data->in_use = true;
789802

790803
crsr = conn_data->crsr;
@@ -1985,14 +1998,16 @@ connections if "clear_all" is true.
19851998
@return number of connection cleaned */
19861999
static
19872000
bool
1988-
innodb_flush_clean_conn(
1989-
/*====================*/
2001+
innodb_flush_sync_conn(
2002+
/*===================*/
19902003
innodb_engine_t* engine, /*!< in/out: InnoDB memcached
19912004
engine */
1992-
const void* cookie) /*!< in: connection cookie */
2005+
const void* cookie, /*!< in: connection cookie */
2006+
bool flush_flag) /*!< in: flush is running or not */
19932007
{
19942008
innodb_conn_data_t* conn_data = NULL;
19952009
innodb_conn_data_t* curr_conn_data;
2010+
bool ret = true;
19962011

19972012
curr_conn_data = engine->server.cookie->get_engine_specific(cookie);
19982013
assert(curr_conn_data);
@@ -2002,19 +2017,35 @@ innodb_flush_clean_conn(
20022017

20032018
while (conn_data) {
20042019
if (conn_data != curr_conn_data && (!conn_data->is_stale)) {
2005-
if (curr_conn_data->thd) {
2020+
if (conn_data->thd) {
20062021
handler_thd_attach(conn_data->thd, NULL);
20072022
}
2008-
innodb_reset_conn(conn_data, false, true,
2009-
engine->enable_binlog);
2023+
LOCK_CURRENT_CONN_IF_NOT_LOCKED(false, conn_data);
2024+
if (flush_flag == false) {
2025+
conn_data->is_flushing = flush_flag;
2026+
UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(false, conn_data);
2027+
conn_data = UT_LIST_GET_NEXT(conn_list, conn_data);
2028+
continue;
2029+
}
2030+
if (!conn_data->in_use) {
2031+
/* Set flushing flag to conn_data for preventing
2032+
it is get by other request. */
2033+
conn_data->is_flushing = flush_flag;
2034+
UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(false, conn_data);
2035+
} else {
2036+
ret = false;
2037+
UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(false, conn_data);
2038+
break;
2039+
}
20102040
}
20112041
conn_data = UT_LIST_GET_NEXT(conn_list, conn_data);
20122042
}
20132043

20142044
if (curr_conn_data->thd) {
20152045
handler_thd_attach(curr_conn_data->thd, NULL);
20162046
}
2017-
return(true);
2047+
2048+
return(ret);
20182049
}
20192050

20202051
/*******************************************************************//**
@@ -2055,6 +2086,9 @@ innodb_flush(
20552086
new opeartion */
20562087
pthread_mutex_lock(&innodb_eng->conn_mutex);
20572088

2089+
/* Lock the flush_mutex for blocking other DMLs. */
2090+
pthread_mutex_lock(&innodb_eng->flush_mutex);
2091+
20582092
conn_data = innodb_eng->server.cookie->get_engine_specific(cookie);
20592093

20602094
if (conn_data) {
@@ -2067,21 +2101,34 @@ innodb_flush(
20672101
IB_LOCK_TABLE_X, true, NULL);
20682102

20692103
if (!conn_data) {
2104+
pthread_mutex_unlock(&innodb_eng->flush_mutex);
20702105
pthread_mutex_unlock(&innodb_eng->conn_mutex);
20712106
return(ENGINE_SUCCESS);
20722107
}
20732108

2074-
innodb_flush_clean_conn(innodb_eng, cookie);
2075-
2109+
/* Commit any previous work on this connection */
20762110
innodb_api_cursor_reset(innodb_eng, conn_data, CONN_OP_FLUSH, true);
2077-
meta_info = conn_data->conn_meta;
2111+
2112+
if (!innodb_flush_sync_conn(innodb_eng, cookie, true)) {
2113+
pthread_mutex_unlock(&innodb_eng->flush_mutex);
2114+
pthread_mutex_unlock(&innodb_eng->conn_mutex);
2115+
innodb_flush_sync_conn(innodb_eng, cookie, false);
2116+
return(ENGINE_TMPFAIL);
2117+
}
20782118

20792119
ib_err = innodb_api_flush(innodb_eng, conn_data,
20802120
meta_info->col_info[CONTAINER_DB].col_name,
20812121
meta_info->col_info[CONTAINER_TABLE].col_name);
20822122

2123+
/* Commit work and release the MDL table. */
2124+
innodb_api_cursor_reset(innodb_eng, conn_data, CONN_OP_FLUSH, true);
2125+
innodb_conn_clean_data(conn_data, false, false);
2126+
2127+
pthread_mutex_unlock(&innodb_eng->flush_mutex);
20832128
pthread_mutex_unlock(&innodb_eng->conn_mutex);
20842129

2130+
innodb_flush_sync_conn(innodb_eng, cookie, false);
2131+
20852132
return((ib_err == DB_SUCCESS) ? ENGINE_SUCCESS : ENGINE_TMPFAIL);
20862133
}
20872134

0 commit comments

Comments
 (0)