From 8db072748fc9beb11fa34fe3efc3e31f17499409 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 9 Nov 2012 20:15:23 +0100 Subject: [PATCH 1/7] add a test case for MySQL Bug #13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ | HANDLE_FATAL_SIGNAL IN STRNLEN --- mysql-test/r/information_schema.result | 2 ++ mysql-test/t/information_schema.test | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 608ada570fb..2d26850808a 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1673,4 +1673,6 @@ SELECT length(CAST(b AS CHAR)) FROM ubig; length(CAST(b AS CHAR)) 20 DROP TABLE ubig; +select 1 from information_schema.tables where table_schema=repeat('a', 2000); +1 End of 5.1 tests. diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index e78b180caf7..a6b07f379ec 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1438,6 +1438,10 @@ SELECT length(CAST(b AS CHAR)) FROM ubig; DROP TABLE ubig; +# +# Bug #13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ | HANDLE_FATAL_SIGNAL IN STRNLEN +# +select 1 from information_schema.tables where table_schema=repeat('a', 2000); --echo End of 5.1 tests. From 094f4cf77890c5a747a57cf2bed149b0b6933507 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 9 Nov 2012 23:51:51 -0800 Subject: [PATCH 2/7] Fixed bug mdev-3845. If triggers are used for an insert/update/delete statement than the values of all virtual columns must be computed as any of them may be used by the triggers. --- mysql-test/suite/vcol/inc/vcol_trigger_sp.inc | 41 +++++++++++++++++++ .../vcol/r/vcol_trigger_sp_innodb.result | 40 ++++++++++++++++++ .../vcol/r/vcol_trigger_sp_myisam.result | 40 ++++++++++++++++++ sql/mysql_priv.h | 3 +- sql/sql_base.cc | 17 ++++++-- sql/sql_delete.cc | 4 +- sql/sql_table.cc | 2 +- sql/sql_update.cc | 8 +++- sql/table.cc | 21 ++++++---- sql/table.h | 7 ++++ 10 files changed, 165 insertions(+), 18 deletions(-) diff --git a/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc b/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc index ddf13fef6a1..eb7e6ad32b9 100644 --- a/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc +++ b/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc @@ -108,3 +108,44 @@ select * from t1; drop table t1,t2; drop procedure p1; + +--echo # +--echo # Bug mdev-3845: values of virtual columns are not computed for triggers +--echo # + +CREATE TABLE t1 ( + a INTEGER UNSIGNED NULL DEFAULT NULL, + b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL +); + +CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL); + +DELIMITER |; + +CREATE TRIGGER t1_ins_aft + AFTER INSERT + ON t1 + FOR EACH ROW +BEGIN + INSERT INTO t2 (c) VALUES (NEW.b); +END | + +CREATE TRIGGER t1_del_bef + BEFORE DELETE + ON t1 + FOR EACH ROW +BEGIN + INSERT INTO t2 (c) VALUES (OLD.b); +END | + +DELIMITER ;| + +INSERT INTO t1 (a) VALUES (1), (2), (3); +SELECT * FROM t2; +DELETE FROM t1; +SELECT * FROM t2; + +DROP TRIGGER t1_ins_aft; +DROP TRIGGER t1_del_bef; +DROP TABLE t1,t2; + diff --git a/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result b/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result index e903bc4eafd..1d78bbf50e4 100644 --- a/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result @@ -85,3 +85,43 @@ a b c 300 30 30 drop table t1,t2; drop procedure p1; +# +# Bug mdev-3845: values of virtual columns are not computed for triggers +# +CREATE TABLE t1 ( +a INTEGER UNSIGNED NULL DEFAULT NULL, +b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL +); +CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL); +CREATE TRIGGER t1_ins_aft +AFTER INSERT +ON t1 +FOR EACH ROW +BEGIN +INSERT INTO t2 (c) VALUES (NEW.b); +END | +CREATE TRIGGER t1_del_bef +BEFORE DELETE +ON t1 +FOR EACH ROW +BEGIN +INSERT INTO t2 (c) VALUES (OLD.b); +END | +INSERT INTO t1 (a) VALUES (1), (2), (3); +SELECT * FROM t2; +c +1 +2 +3 +DELETE FROM t1; +SELECT * FROM t2; +c +1 +2 +3 +1 +2 +3 +DROP TRIGGER t1_ins_aft; +DROP TRIGGER t1_del_bef; +DROP TABLE t1,t2; diff --git a/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result b/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result index c2a66d656b5..77efa8fe6b9 100644 --- a/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result @@ -85,3 +85,43 @@ a b c 300 30 30 drop table t1,t2; drop procedure p1; +# +# Bug mdev-3845: values of virtual columns are not computed for triggers +# +CREATE TABLE t1 ( +a INTEGER UNSIGNED NULL DEFAULT NULL, +b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL +); +CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL); +CREATE TRIGGER t1_ins_aft +AFTER INSERT +ON t1 +FOR EACH ROW +BEGIN +INSERT INTO t2 (c) VALUES (NEW.b); +END | +CREATE TRIGGER t1_del_bef +BEFORE DELETE +ON t1 +FOR EACH ROW +BEGIN +INSERT INTO t2 (c) VALUES (OLD.b); +END | +INSERT INTO t1 (a) VALUES (1), (2), (3); +SELECT * FROM t2; +c +1 +2 +3 +DELETE FROM t1; +SELECT * FROM t2; +c +1 +2 +3 +1 +2 +3 +DROP TRIGGER t1_ins_aft; +DROP TRIGGER t1_del_bef; +DROP TABLE t1,t2; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index addb29861fc..73b8ad86426 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1366,7 +1366,8 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, bool allow_rowid, uint *cached_field_index_ptr); Field * find_field_in_table_sef(TABLE *table, const char *name); -int update_virtual_fields(THD *thd, TABLE *table, bool ignore_stored= FALSE); +int update_virtual_fields(THD *thd, TABLE *table, + enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ); #endif /* MYSQL_SERVER */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f45403696be..32a5bd8356f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8460,7 +8460,9 @@ fill_record(THD * thd, List &fields, List &values, { if (vcol_table->vfield) { - if (update_virtual_fields(thd, vcol_table, TRUE)) + if (update_virtual_fields(thd, vcol_table, + vcol_table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_WRITE)) goto err; } } @@ -8524,7 +8526,9 @@ fill_record_n_invoke_before_triggers(THD *thd, List &fields, if (item_field && item_field->field && (table= item_field->field->table) && table->vfield) - result= update_virtual_fields(thd, table, TRUE); + result= update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_WRITE); } } return result; @@ -8604,7 +8608,10 @@ fill_record(THD *thd, Field **ptr, List &values, bool ignore_errors) } /* Update virtual fields*/ thd->abort_on_warning= FALSE; - if (table->vfield && update_virtual_fields(thd, table, TRUE)) + if (table->vfield && + update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_WRITE)) goto err; thd->abort_on_warning= abort_on_warning_saved; DBUG_RETURN(thd->is_error()); @@ -8657,7 +8664,9 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr, { TABLE *table= (*ptr)->table; if (table->vfield) - result= update_virtual_fields(thd, table, TRUE); + result= update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_WRITE); } return result; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 72a5b9703b3..90ca139d17b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -313,7 +313,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, while (!(error=info.read_record(&info)) && !thd->killed && ! thd->is_error()) { - update_virtual_fields(thd, table); + update_virtual_fields(thd, table, + triggers_applicable ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_READ); thd->examined_row_count++; // thd->is_error() is tested to disallow delete row on error if (!select || select->skip_record(thd) > 0) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6b709915283..9b9ee0a743d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -8066,7 +8066,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, copy_ptr->do_copy(copy_ptr); } prev_insert_id= to->file->next_insert_id; - update_virtual_fields(thd, to, TRUE); + update_virtual_fields(thd, to, VCOL_UPDATE_FOR_WRITE); if (thd->is_error()) { error= 1; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b3c001849b5..56b2c508fbc 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -490,7 +490,9 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { - update_virtual_fields(thd, table); + update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_READ); thd->examined_row_count++; if (!select || (error= select->skip_record(thd)) > 0) { @@ -605,7 +607,9 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { - update_virtual_fields(thd, table); + update_virtual_fields(thd, table, + table->triggers ? VCOL_UPDATE_ALL : + VCOL_UPDATE_FOR_READ); thd->examined_row_count++; if (!select || select->skip_record(thd) > 0) { diff --git a/sql/table.cc b/sql/table.cc index d950b7a3a4e..5c1e27b87c7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5500,22 +5500,25 @@ size_t max_row_length(TABLE *table, const uchar *data) @param thd Thread handle @param table The TABLE object - @param for_write Requests to compute only fields needed for write + @param vcol_update_mode Specifies what virtual column are computed @details The function computes the values of the virtual columns of the table and stores them in the table record buffer. - Only fields from vcol_set are computed, and, when the flag for_write is not - set to TRUE, a virtual field is computed only if it's not stored. - The flag for_write is set to TRUE for row insert/update operations. - + If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are + computed. Otherwise, only fields from vcol_set are computed: all of them, + if vcol_update_mode is set to VCOL_UPDATE_FOR_WRITE, and, only those with + the stored_in_db flag set to false, if vcol_update_mode is equal to + VCOL_UPDATE_FOR_READ. + @retval 0 Success @retval >0 Error occurred when storing a virtual field value */ -int update_virtual_fields(THD *thd, TABLE *table, bool for_write) +int update_virtual_fields(THD *thd, TABLE *table, + enum enum_vcol_update_mode vcol_update_mode) { DBUG_ENTER("update_virtual_fields"); Field **vfield_ptr, *vfield; @@ -5529,9 +5532,9 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write) { vfield= (*vfield_ptr); DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item); - /* Only update those fields that are marked in the vcol_set bitmap */ - if (bitmap_is_set(table->vcol_set, vfield->field_index) && - (for_write || !vfield->stored_in_db)) + if ((bitmap_is_set(table->vcol_set, vfield->field_index) && + (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) || + vcol_update_mode == VCOL_UPDATE_ALL) { /* Compute the actual value of the virtual fields */ error= vfield->vcol_info->expr_item->save_in_field(vfield, 0); diff --git a/sql/table.h b/sql/table.h index c1a4e952f7b..80544ef3d89 100644 --- a/sql/table.h +++ b/sql/table.h @@ -156,6 +156,13 @@ enum frm_type_enum enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP }; +enum enum_vcol_update_mode +{ + VCOL_UPDATE_FOR_READ= 0, + VCOL_UPDATE_FOR_WRITE, + VCOL_UPDATE_ALL +}; + typedef struct st_filesort_info { IO_CACHE *io_cache; /* If sorted through filesort */ From 353130204dead31c311cfc2877278640df84a5ee Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 10 Nov 2012 20:36:18 +0100 Subject: [PATCH 3/7] MDEV-3849 - 1 bytes stack overwrite in normalize_dirname(). Take into account that length of strings passed down to this function can be up to FN_REFLEN+1 bytes. including terminating zero. The overwrite was caused by incomplete fix to MySQL Bug # 44834 --- mysys/mf_pack.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index 86fd61537e7..e6b576b6d96 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -35,7 +35,7 @@ void pack_dirname(char * to, const char *from) int cwd_err; size_t d_length,length,UNINIT_VAR(buff_length); char * start; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; DBUG_ENTER("pack_dirname"); (void) intern_filename(to,from); /* Change to intern name */ @@ -132,7 +132,7 @@ size_t cleanup_dirname(register char *to, const char *from) reg3 char * from_ptr; reg4 char * start; char parent[5], /* for "FN_PARENTDIR" */ - buff[FN_REFLEN+1],*end_parentdir; + buff[FN_REFLEN + 1],*end_parentdir; #ifdef BACKSLASH_MBTAIL CHARSET_INFO *fs= fs_character_set(); #endif @@ -245,7 +245,7 @@ my_bool my_use_symdir=0; /* Set this if you want to use symdirs */ #ifdef USE_SYMDIR void symdirget(char *dir) { - char buff[FN_REFLEN+1]; + char buff[FN_REFLEN + 1]; char *pos=strend(dir); if (dir[0] && pos[-1] != FN_DEVCHAR && my_access(dir, F_OK)) { @@ -295,7 +295,7 @@ void symdirget(char *dir) size_t normalize_dirname(char *to, const char *from) { size_t length; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; DBUG_ENTER("normalize_dirname"); /* @@ -423,7 +423,7 @@ static char * NEAR_F expand_tilde(char * *path) size_t unpack_filename(char * to, const char *from) { size_t length, n_length, buff_length; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; DBUG_ENTER("unpack_filename"); length=dirname_part(buff, from, &buff_length);/* copy & convert dirname */ @@ -459,7 +459,7 @@ size_t system_filename(char * to, const char *from) int libchar_found; size_t length; char * to_pos,from_pos,pos; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; DBUG_ENTER("system_filename"); libchar_found=0; @@ -516,7 +516,7 @@ size_t system_filename(char * to, const char *from) char *intern_filename(char *to, const char *from) { size_t length, to_length; - char buff[FN_REFLEN]; + char buff[FN_REFLEN + 1]; if (from == to) { /* Dirname may destroy from */ strmov(buff,from); From e679dfcafc630e2dbe506d0001322055d7684e03 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 12 Nov 2012 19:56:51 +0100 Subject: [PATCH 4/7] followup fixes for MySQL Bug #13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ | HANDLE_FATAL_SIGNAL IN STRNLEN --- mysql-test/r/information_schema.result | 4 ++++ mysql-test/t/information_schema.test | 7 +++++++ sql/sql_acl.cc | 20 ++++++++++++++++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 2d26850808a..cacb18ba728 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1675,4 +1675,8 @@ length(CAST(b AS CHAR)) DROP TABLE ubig; select 1 from information_schema.tables where table_schema=repeat('a', 2000); 1 +grant usage on *.* to mysqltest_1@localhost; +select 1 from information_schema.tables where table_schema=repeat('a', 2000); +1 +drop user mysqltest_1@localhost; End of 5.1 tests. diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index a6b07f379ec..ae733443479 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1442,6 +1442,13 @@ DROP TABLE ubig; # Bug #13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ | HANDLE_FATAL_SIGNAL IN STRNLEN # select 1 from information_schema.tables where table_schema=repeat('a', 2000); +grant usage on *.* to mysqltest_1@localhost; +connect (con1, localhost, mysqltest_1,,); +connection con1; +select 1 from information_schema.tables where table_schema=repeat('a', 2000); +connection default; +disconnect con1; +drop user mysqltest_1@localhost; --echo End of 5.1 tests. diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 89b70032642..020aa042722 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1353,14 +1353,20 @@ ulong acl_get(const char *host, const char *ip, acl_entry *entry; DBUG_ENTER("acl_get"); - VOID(pthread_mutex_lock(&acl_cache->lock)); - end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db); + tmp_db= strmov(strmov(key, ip ? ip : "") + 1, user) + 1; + end= strnmov(tmp_db, db, key + sizeof(key) - tmp_db); + + if (end >= key + sizeof(key)) // db name was truncated + DBUG_RETURN(0); // no privileges for an invalid db name + if (lower_case_table_names) { my_casedn_str(files_charset_info, tmp_db); db=tmp_db; } key_length= (size_t) (end-key); + + VOID(pthread_mutex_lock(&acl_cache->lock)); if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search((uchar*) key, key_length))) { @@ -4331,11 +4337,17 @@ static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash) bool check_grant_db(THD *thd,const char *db) { Security_context *sctx= thd->security_ctx; - char helping [SAFE_NAME_LEN + USERNAME_LENGTH+2]; + char helping [SAFE_NAME_LEN + USERNAME_LENGTH+2], *end; uint len; bool error= TRUE; - len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1; + end= strmov(helping, sctx->priv_user) + 1; + end= strnmov(end, db, helping + sizeof(helping) - end); + + if (end >= helping + sizeof(helping)) // db name was truncated + return 1; // no privileges for an invalid db name + + len= (uint) (end - helping) + 1; rw_rdlock(&LOCK_grant); From 632dc05ded27eeb0976e7a67310749ab4635614b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 17 Nov 2012 19:04:13 +0100 Subject: [PATCH 5/7] MDEV-3850 too early pthread_mutex_unlock in TC_LOG_MMAP::log_xid --- sql/log.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index 4c21ac4c571..eb248c63b19 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -5710,12 +5710,9 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid) pthread_mutex_unlock(&LOCK_active); pthread_mutex_lock(&p->lock); p->waiters++; - for (;;) + while (p->state == DIRTY && syncing) { - int not_dirty = p->state != DIRTY; pthread_mutex_unlock(&p->lock); - if (not_dirty || !syncing) - break; pthread_cond_wait(&p->cond, &LOCK_sync); pthread_mutex_lock(&p->lock); } From 9e7d870b360b165ac7960814a2fa5bf6011eab1a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 19 Nov 2012 11:18:40 +0100 Subject: [PATCH 6/7] potential crash in the feedback plugin --- plugin/feedback/url_http.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugin/feedback/url_http.cc b/plugin/feedback/url_http.cc index 71b67a52807..b0028292707 100644 --- a/plugin/feedback/url_http.cc +++ b/plugin/feedback/url_http.cc @@ -258,18 +258,21 @@ int Url_http::send(const char* data, size_t data_length) Extract the first string between

...

tags and put it as a server reply into the error log. */ + len= 0; for (;;) { - size_t i= vio_read(vio, (uchar*)buf + len, sizeof(buf) - len - 1); + size_t i= sizeof(buf) - len - 1; + if (i) + i= vio_read(vio, (uchar*)buf + len, i); if ((int)i <= 0) break; len+= i; } - if (len && len < sizeof(buf)) + if (len) { char *from; - buf[len+1]= 0; // safety + buf[len]= 0; // safety if ((from= strstr(buf, "

"))) { From 47c5018f592b61b5e000842bdf5862ff458de488 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Nov 2012 13:28:53 +0100 Subject: [PATCH 7/7] MDEV-3861: assertions in TC_LOG_MMAP. Fix some problems in the TC_LOG_MMAP commit processing, which could lead to assertions in some cases. Problems are mostly reproducible in MariaDB 10.0 with asynchroneous commit checkpoints, but most of the problems were present in earlier versions also. --- sql/log.cc | 19 ++++++++++--------- sql/log.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index eb248c63b19..e44f8ff3067 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -5550,8 +5550,9 @@ int TC_LOG_MMAP::open(const char *opt_name) syncing= 0; active=pages; + DBUG_ASSERT(npages >= 2); pool=pages+1; - pool_last=pages+npages-1; + pool_last_ptr= &((pages+npages-1)->next); return 0; @@ -5582,8 +5583,8 @@ void TC_LOG_MMAP::get_active_from_pool() do { best_p= p= &pool; - if ((*p)->waiters == 0) // can the first page be used ? - break; // yes - take it. + if ((*p)->waiters == 0 && (*p)->free > 0) // can the first page be used ? + break; // yes - take it. best_free=0; // no - trying second strategy for (p=&(*p)->next; *p; p=&(*p)->next) @@ -5600,10 +5601,10 @@ void TC_LOG_MMAP::get_active_from_pool() safe_mutex_assert_owner(&LOCK_active); active=*best_p; - if ((*best_p)->next) // unlink the page from the pool - *best_p=(*best_p)->next; - else - pool_last=*best_p; + /* Unlink the page from the pool. */ + if (!(*best_p)->next) + pool_last_ptr= best_p; + *best_p=(*best_p)->next; pthread_mutex_unlock(&LOCK_pool); pthread_mutex_lock(&active->lock); @@ -5764,8 +5765,8 @@ int TC_LOG_MMAP::sync() /* page is synced. let's move it to the pool */ pthread_mutex_lock(&LOCK_pool); - pool_last->next=syncing; - pool_last=syncing; + (*pool_last_ptr)=syncing; + pool_last_ptr=&(syncing->next); syncing->next=0; syncing->state= err ? ERROR : POOL; pthread_cond_signal(&COND_pool); // in case somebody's waiting diff --git a/sql/log.h b/sql/log.h index f42ef514307..9fb233fed86 100644 --- a/sql/log.h +++ b/sql/log.h @@ -81,7 +81,7 @@ class TC_LOG_MMAP: public TC_LOG my_off_t file_length; uint npages, inited; uchar *data; - struct st_page *pages, *syncing, *active, *pool, *pool_last; + struct st_page *pages, *syncing, *active, *pool, **pool_last_ptr; /* note that, e.g. LOCK_active is only used to protect 'active' pointer, to protect the content of the active page