diff --git a/VERSION b/VERSION index 885bb6f9f3f49..02be89b1fea72 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=11 MYSQL_VERSION_MINOR=8 -MYSQL_VERSION_PATCH=7 +MYSQL_VERSION_PATCH=9 SERVER_MATURITY=stable diff --git a/client/mysqldump.cc b/client/mysqldump.cc index e81e5cb878103..ebe41851b9150 100644 --- a/client/mysqldump.cc +++ b/client/mysqldump.cc @@ -40,7 +40,7 @@ */ /* on merge conflict, bump to a higher version again */ -#define VER "10.19" +#define VER "10.20" /** First mysql version supporting sequences. @@ -1428,7 +1428,6 @@ static void DB_error(MYSQL *mysql_arg, const char *when) } - /* Prints out an error message and kills the process. @@ -1491,7 +1490,6 @@ static void maybe_die(int error_num, const char* fmt_reason, ...) } - /* Sends a query to server, optionally reads result, prints error message if some. @@ -1502,27 +1500,64 @@ static void maybe_die(int error_num, const char* fmt_reason, ...) res if non zero, result will be put there with mysql_store_result() query query to send to server + no_parse_error Do not print error message for parse errors RETURN VALUES 0 query sending and (if res!=0) result reading went ok 1 error + -1 Syntax/parse error (for retry code) */ static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res, - const char *query) + const char *query, + bool no_parse_error = false) { DBUG_ASSERT(mysql_con); if (mysql_query(mysql_con, query) || (res && !((*res)= mysql_store_result(mysql_con)))) { + if (no_parse_error && mysql_errno(mysql_con) == ER_PARSE_ERROR) + return -1; maybe_die(EX_MYSQLERR, "Couldn't execute '%s': %s (%d)", - query, mysql_error(mysql_con), mysql_errno(mysql_con)); + query, mysql_error(mysql_con), mysql_errno(mysql_con)); return 1; } return 0; } +/* + Sends a query to server. In case of parse error try another syntax +*/ + +static int mysql_query_with_retry(MYSQL *mysql_con, MYSQL_RES **res, + const char *query1, const char *query2) +{ + int error; + if ((error= mysql_query_with_error_report(mysql_con, res, query1, 1)) == -1) + error= mysql_query_with_error_report(mysql_con, res, query2, 0); + return error; +} + +/* + Get slave status from server. + + Note that MySQL server does not support 'SHOW ALL' and + multi_source should thus not be set when dumping from MySQL +*/ + +static int show_slave_status(MYSQL *mysql_con, MYSQL_RES **res) +{ + return (mysql_query_with_retry(mysql_con, res, + (multi_source ? + "SHOW ALL REPLICAS STATUS" : + "SHOW REPLICA STATUS"), + (multi_source ? + "SHOW ALL SLAVES STATUS" : + "SHOW SLAVE STATUS"))); +} + + static int fetch_db_collation(const char *db_name, char *db_cl_name, int db_cl_size) @@ -6389,8 +6424,9 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos, } else { - if (mysql_query_with_error_report(mysql_con, &master, - "SHOW MASTER STATUS")) + if (mysql_query_with_retry(mysql_con, &master, + "SHOW MASTER STATUS", + "SHOW BINARY LOG STATUS")) return 1; row= mysql_fetch_row(master); @@ -6477,10 +6513,7 @@ static int do_stop_slave_sql(MYSQL *mysql_con) !slave_status_res // do_stop_slave_sql() should only be called once ); - if (mysql_query_with_error_report(mysql_con, &slave_status_res, - multi_source ? - "SHOW ALL SLAVES STATUS" : - "SHOW SLAVE STATUS")) + if (show_slave_status(mysql_con, &slave_status_res)) return(1); /* Loop over all slaves */ @@ -6493,7 +6526,8 @@ static int do_stop_slave_sql(MYSQL *mysql_con) { char query[160]; if (multi_source) - snprintf(query, sizeof(query), "STOP SLAVE '%.80s' SQL_THREAD", row[0]); + snprintf(query, sizeof(query), "STOP SLAVE '%.80s' SQL_THREAD", + row[0]); else strmov(query, "STOP SLAVE SQL_THREAD"); @@ -6542,10 +6576,7 @@ static int do_show_slave_status(MYSQL *mysql_con, int have_mariadb_gtid, const char *gtid_comment_prefix= (use_gtid ? comment_prefix : "-- "); const char *nogtid_comment_prefix= (!use_gtid ? comment_prefix : "-- "); - if (mysql_query_with_error_report(mysql_con, &slave, - multi_source ? - "SHOW ALL SLAVES STATUS" : - "SHOW SLAVE STATUS")) + if (show_slave_status(mysql_con, &slave)) { if (!ignore_errors) { @@ -6705,8 +6736,9 @@ static int get_bin_log_name(MYSQL *mysql_con, MYSQL_RES *res; MYSQL_ROW row; - if (mysql_query(mysql_con, "SHOW MASTER STATUS") || - !(res= mysql_store_result(mysql))) + if (mysql_query_with_retry(mysql_con, &res, + "SHOW MASTER STATUS", + "SHOW BINARY LOG STATUS")) return 1; if (!(row= mysql_fetch_row(res))) diff --git a/cmake/generate_sbom.cmake b/cmake/generate_sbom.cmake index a0fbc99756eaa..c45427be737ec 100644 --- a/cmake/generate_sbom.cmake +++ b/cmake/generate_sbom.cmake @@ -98,7 +98,7 @@ FUNCTION (sbom_get_supplier repo_name repo_user varname) ELSEIF (repo_name MATCHES "boost") SET(${varname} "Boost.org" PARENT_SCOPE) ELSEIF(repo_user MATCHES "mariadb-corporation|mariadb") - SET(${varname} "MariaDB") + SET(${varname} "MariaDB" PARENT_SCOPE) ELSE() # Capitalize just first letter in repo_user STRING(SUBSTRING "${repo_user}" 0 1 first_letter) diff --git a/extra/mariadb_migrate_config_file.c b/extra/mariadb_migrate_config_file.c index a69e8fdfa4196..f24c1e5ee859b 100644 --- a/extra/mariadb_migrate_config_file.c +++ b/extra/mariadb_migrate_config_file.c @@ -135,7 +135,9 @@ static size_t global_copied_lines=0, global_unsupported_lines= 0; static size_t global_mariadbd_additions= 0; static PSI_memory_key key_memory_upgrade_config; +#ifdef HAVE_PSI_FILE_INTERFACE static PSI_file_key key_file_cnf; +#endif static size_t global_update_count= 0; static my_bool give_error_for_missing_files= 0; static my_bool opt_mariadbd_testing; diff --git a/include/my_atomic_wrapper.h b/include/my_atomic_wrapper.h index 7b35b14d3b79a..042b9966c4bd8 100644 --- a/include/my_atomic_wrapper.h +++ b/include/my_atomic_wrapper.h @@ -63,6 +63,10 @@ template class Atomic_relaxed std::memory_order o1= std::memory_order_relaxed, std::memory_order o2= std::memory_order_relaxed) { return m.compare_exchange_strong(i1, i2, o1, o2); } + bool compare_exchange_weak(Type& i1, const Type i2, + std::memory_order o1= std::memory_order_relaxed, + std::memory_order o2= std::memory_order_relaxed) + { return m.compare_exchange_weak(i1, i2, o1, o2); } Type exchange(const Type i, std::memory_order o= std::memory_order_relaxed) { return m.exchange(i, o); } }; diff --git a/mysql-test/main/create_drop_binlog.test b/mysql-test/main/create_drop_binlog.test index 6b2b1bbf1f5fa..2075820135738 100644 --- a/mysql-test/main/create_drop_binlog.test +++ b/mysql-test/main/create_drop_binlog.test @@ -7,7 +7,7 @@ reset master; --let $pos=`select $binlog_start_pos + 73` --let $binlog_file=query_get_value(SHOW MASTER STATUS, File, 1) ---let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) +--let $binlog_start=query_get_value(SHOW BINARY LOG STATUS, Position, 1) CREATE OR REPLACE DATABASE d1; CREATE OR REPLACE DATABASE d1; diff --git a/mysql-test/main/max_session_mem_used.test b/mysql-test/main/max_session_mem_used.test index 4cad0dab49048..99ab5c26b7aef 100644 --- a/mysql-test/main/max_session_mem_used.test +++ b/mysql-test/main/max_session_mem_used.test @@ -1,6 +1,6 @@ # memory usage is sensitive to valgrind/ps-protocol/embedded source include/not_msan.inc; -source include/not_valgrind.inc; +source include/not_valgrind_build.inc; source include/no_protocol.inc; source include/not_embedded.inc; source include/have_64bit.inc; diff --git a/mysql-test/main/show_check.result b/mysql-test/main/show_check.result index d3cfb09aef14f..ed732f264e664 100644 --- a/mysql-test/main/show_check.result +++ b/mysql-test/main/show_check.result @@ -846,6 +846,7 @@ show create database test; show create table t1; show create view v1; show master status; +show binary log status; show slave status; show create procedure p1; show create function f1; diff --git a/mysql-test/main/show_check.test b/mysql-test/main/show_check.test index e5457a25fb70b..636697007a314 100644 --- a/mysql-test/main/show_check.test +++ b/mysql-test/main/show_check.test @@ -656,6 +656,7 @@ show create database test; show create table t1; show create view v1; show master status; +show binary log status; show slave status; show create procedure p1; show create function f1; diff --git a/sql/lex.h b/sql/lex.h index d420430545f29..2a35d057d63be 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -355,6 +355,7 @@ SYMBOL symbols[] = { { "LOCK", SYM(LOCK_SYM)}, { "LOCKED", SYM(LOCKED_SYM)}, { "LOCKS", SYM(LOCKS_SYM)}, + { "LOG", SYM(LOG_SYM)}, { "LOGFILE", SYM(LOGFILE_SYM)}, { "LOGS", SYM(LOGS_SYM)}, { "LONG", SYM(LONG_SYM)}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 20352ee590052..21eb9e9c9bff1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -933,6 +933,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token LOCKS_SYM %token LOGFILE_SYM %token LOGS_SYM +%token LOG_SYM %token MASTER_CONNECT_RETRY_SYM %token MASTER_DELAY_SYM %token MASTER_GTID_POS_SYM @@ -14546,6 +14547,10 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_BINLOG_STAT; } + | BINARY LOG_SYM STATUS_SYM + { + Lex->sql_command = SQLCOM_SHOW_BINLOG_STAT; + } | ALL SLAVES STATUS_SYM { LEX *lex= Lex; @@ -16563,6 +16568,7 @@ keyword_func_sp_var_and_label: | LIST_SYM | LOCKED_SYM | LOCKS_SYM + | LOG_SYM | LOGFILE_SYM | LOGS_SYM | MAX_ROWS diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index b18f890abc7d2..f0ef7a43fc506 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -61,9 +61,54 @@ static constexpr ulint buf_flush_lsn_scan_factor = 3; /** Average redo generation rate */ static lsn_t lsn_avg_rate = 0; -/** Target oldest_modification for the page cleaner background flushing; -writes are protected by buf_pool.flush_list_mutex */ -static Atomic_relaxed buf_flush_async_lsn; +namespace { +/** Wrapper around Atomic_relaxed that blocks direct operator= +so every write goes through its controlled CAS-based methods. */ +class async_flush_lsn +{ + Atomic_relaxed m_lsn; +public: + operator lsn_t() const noexcept { return m_lsn; } + lsn_t load() const noexcept { return m_lsn; } + + /** Initialize at startup (single-threaded). */ + void init() noexcept { m_lsn= 0; } + + /** Monotonic-max lock-free bump. + @param lsn new target + @return whether the target was bumped */ + bool bump(lsn_t lsn) noexcept + { + lsn_t snapshot= m_lsn.load(); + while (snapshot < lsn) + if (m_lsn.compare_exchange_weak(snapshot, lsn)) + return true; + return false; + } + + /** Clear via snapshot+CAS iff the freshly snapshotted target is at + most threshold; a concurrent bump() between the snapshot and the CAS + is preserved across the clear. + @param threshold clear iff the fresh snapshot is at most this value */ + void try_clear_if_at_most(lsn_t threshold) noexcept + { + lsn_t snapshot= m_lsn.load(); + if (threshold >= snapshot) + m_lsn.compare_exchange_strong(snapshot, 0); + } + + /** Clear via CAS using the caller's expected value; a concurrent + bump() that moved the target away from expected is preserved across + the clear. */ + void try_clear(lsn_t expected) noexcept + { m_lsn.compare_exchange_strong(expected, 0); } +}; +} +/** Target oldest_modification for the page cleaner background flushing. +Bumped lock-free via monotonic-max CAS-loop from buf_flush_ahead(); +cleared with CAS under buf_pool.flush_list_mutex from +buf_flush_page_cleaner() and buf_flush_sync_for_checkpoint(). */ +static async_flush_lsn buf_flush_async_lsn; /** Target oldest_modification for the page cleaner furious flushing; writes are protected by buf_pool.flush_list_mutex */ static Atomic_relaxed buf_flush_sync_lsn; @@ -112,6 +157,7 @@ static void buf_flush_validate_skip() noexcept void buf_pool_t::page_cleaner_wakeup(bool for_LRU) noexcept { + mysql_mutex_assert_owner(&flush_list_mutex); ut_d(buf_flush_validate_skip()); if (!page_cleaner_idle()) { @@ -154,7 +200,7 @@ void buf_pool_t::page_cleaner_wakeup(bool for_LRU) noexcept last_activity_count == srv_get_activity_count())) || srv_max_buf_pool_modified_pct <= dirty_pct) { - page_cleaner_status-= PAGE_CLEANER_IDLE; + page_cleaner_idle_flag= false; pthread_cond_signal(&do_flush_list); } } @@ -2114,33 +2160,50 @@ ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious) noexcept DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", return;); - Atomic_relaxed &limit= furious - ? buf_flush_sync_lsn : buf_flush_async_lsn; + if (!furious) + { + if (!buf_flush_async_lsn.bump(lsn)) + return; + + /* In non-furious mode, concurrent writes to the log will remain + possible, and we are gently requesting buf_flush_page_cleaner() + to do more work to avoid a later call with furious=true. + We will only wake the buf_flush_page_cleaner() from an indefinite + my_cond_wait(), but we will not disturb the regular 1-second sleep. + + To reduce contention for a gentle request case, the idle flag of + buf_pool is read outside of a buf_pool.flush_list_mutex critical + section, allowing early return. + + If the decision to return early was (unlikely) wrong, subsequent + wake-side paths (including further buf_flush_ahead() calls under + redo-log pressure) are expected to perform the wake eventually. */ + if (!buf_pool.page_cleaner_idle()) + return; + + /* Signal under buf_pool.flush_list_mutex. */ + mysql_mutex_lock(&buf_pool.flush_list_mutex); + goto wake; + } - if (limit < lsn) + /* The furious path forces a log checkpoint via + log_sys.set_check_for_checkpoint(true), so the buf_flush_sync_lsn + bump, the checkpoint flag, and the cleaner wake must all be observed + together by any thread synchronising on buf_pool.flush_list_mutex. */ + if (buf_flush_sync_lsn < lsn) { mysql_mutex_lock(&buf_pool.flush_list_mutex); - if (limit < lsn) + if (buf_flush_sync_lsn < lsn) { - limit= lsn; - if (furious) - { - /* Request any concurrent threads to wait for this batch to complete, - in log_free_check(). */ - log_sys.set_check_for_checkpoint(true); - /* Immediately wake up buf_flush_page_cleaner(), even when it - is in the middle of a 1-second my_cond_timedwait(). */ - wake: - buf_pool.page_cleaner_set_idle(false); - pthread_cond_signal(&buf_pool.do_flush_list); - } - else if (buf_pool.page_cleaner_idle()) - /* In non-furious mode, concurrent writes to the log will remain - possible, and we are gently requesting buf_flush_page_cleaner() - to do more work to avoid a later call with furious=true. - We will only wake the buf_flush_page_cleaner() from an indefinite - my_cond_wait(), but we will not disturb the regular 1-second sleep. */ - goto wake; + buf_flush_sync_lsn= lsn; + /* Request any concurrent threads to wait for this batch to complete, + in log_free_check(). */ + log_sys.set_check_for_checkpoint(true); + /* Immediately wake up buf_flush_page_cleaner(), even when it + is in the middle of a 1-second my_cond_timedwait(). */ + wake: + buf_pool.page_cleaner_set_idle(false); + pthread_cond_signal(&buf_pool.do_flush_list); } mysql_mutex_unlock(&buf_pool.flush_list_mutex); } @@ -2230,8 +2293,8 @@ static void buf_flush_sync_for_checkpoint(lsn_t lsn) noexcept /* After attempting log checkpoint, check if we have reached our target. */ if (measure >= buf_flush_sync_lsn) buf_flush_sync_lsn= 0; - else if (measure >= buf_flush_async_lsn) - buf_flush_async_lsn= 0; + else + buf_flush_async_lsn.try_clear_if_at_most(measure); log_sys.latch.wr_unlock(); /* wake up buf_flush_wait() */ @@ -2588,7 +2651,10 @@ static void buf_flush_page_cleaner() noexcept if (UNIV_UNLIKELY(soft_lsn_limit != 0)) { if (oldest_lsn >= soft_lsn_limit) - buf_flush_async_lsn= soft_lsn_limit= 0; + { + buf_flush_async_lsn.try_clear(soft_lsn_limit); + soft_lsn_limit= 0; + } } else if (buf_pool.need_LRU_eviction()) { @@ -2611,8 +2677,7 @@ static void buf_flush_page_cleaner() noexcept oldest_lsn= buf_pool.get_oldest_modification(0); if (!oldest_lsn) goto fully_unemployed; - if (oldest_lsn >= buf_flush_async_lsn) - buf_flush_async_lsn= 0; + buf_flush_async_lsn.try_clear_if_at_most(oldest_lsn); buf_pool.page_cleaner_set_idle(false); goto set_almost_idle; } @@ -2658,6 +2723,14 @@ static void buf_flush_page_cleaner() noexcept } else if (dirty_pct < srv_max_buf_pool_modified_pct) possibly_unemployed: + /* Snapshot-based; no coordination with concurrent lock-free + buf_flush_ahead() bumpers. A bumper that observed + page_cleaner_idle()==false earlier in this iteration took its + early return; flipping idle=true here leaves its target + unacknowledged until another wake path fires. Same premise as the + bumper's early return: under sustained redo-log pressure, + subsequent buf_flush_ahead() calls observe + page_cleaner_idle()==true and take the wake path. */ if (!soft_lsn_limit && !af_needed_for_redo(oldest_lsn)) goto set_idle; @@ -2763,7 +2836,7 @@ ATTRIBUTE_COLD void buf_flush_page_cleaner_init() noexcept ut_ad(srv_operation <= SRV_OPERATION_EXPORT_RESTORED || srv_operation == SRV_OPERATION_RESTORE || srv_operation == SRV_OPERATION_RESTORE_EXPORT); - buf_flush_async_lsn= 0; + buf_flush_async_lsn.init(); buf_flush_sync_lsn= 0; buf_page_cleaner_is_active= true; std::thread(buf_flush_page_cleaner).detach(); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a38ca1ce29cf0..410c51b207477 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1198,31 +1198,20 @@ innobase_commit_by_xid( XID* xid); /*!< in: X/Open XA transaction identification */ #ifndef EMBEDDED_LIBRARY -/*******************************************************************//** -This function is used to rollback one X/Open XA distributed transaction -which is in the prepared state asynchronously. - -It only set the transaction's status to ACTIVE and persist the status. -The transaction will be rolled back by background rollback thread. +/** + In binlog recovery, persistently mark that a transaction will be + rolled back. -@return 0 or error number + @param xid Internal MySQLXid identificier + @return 0 or error number */ -static -int -innobase_recover_rollback_by_xid( -/*===================*/ - const XID* xid); /*!< in: X/Open XA transaction - identification */ -/*******************************************************************//** - This function is called after tc log is opened(typically binlog recovery) - has done. It starts rollback thread to rollback the transactions - have been changed from PREPARED to ACTIVE. - - @return 0 or error number +static int innobase_recover_rollback_by_xid(const XID *xid) noexcept; +/** + Signal that the binlog based recovery is completed and request + the completion of the rollback of any transactions on which + innobase_recover_rollback_by_xid() was invoked. */ -static -void -innobase_tc_log_recovery_done(); +static void innobase_tc_log_recovery_done() noexcept; #endif @@ -17279,18 +17268,7 @@ innobase_commit_by_xid( } #ifndef EMBEDDED_LIBRARY -/** - This function is used to rollback one X/Open XA distributed transaction - which is in the prepared state asynchronously. - - It only set the transaction's status to ACTIVE and persist the status. - The transaction will be rolled back by background rollback thread. - - @param xid X/Open XA transaction identification - - @return 0 or error number -*/ -static int innobase_recover_rollback_by_xid(const XID *xid) +static int innobase_recover_rollback_by_xid(const XID *xid) noexcept { DBUG_EXECUTE_IF("innobase_xa_fail", return XAER_RMFAIL;); @@ -17336,7 +17314,7 @@ static int innobase_recover_rollback_by_xid(const XID *xid) return 0; } -static void innobase_tc_log_recovery_done() +static void innobase_tc_log_recovery_done() noexcept { if (high_level_read_only) return; diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 8140b1b7a0f36..a2dc7e8d42c04 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -1532,13 +1532,18 @@ class buf_pool_t TPOOL_SUPPRESS_TSAN void add_flush_list_requests(size_t size) { ut_ad(size); flush_list_requests+= size; } private: - static constexpr unsigned PAGE_CLEANER_IDLE= 1; - static constexpr unsigned FLUSH_LIST_ACTIVE= 2; - static constexpr unsigned LRU_FLUSH= 4; + static constexpr unsigned FLUSH_LIST_ACTIVE= 1; + static constexpr unsigned LRU_FLUSH= 2; - /** Number of pending LRU flush * LRU_FLUSH + - PAGE_CLEANER_IDLE + FLUSH_LIST_ACTIVE flags */ + /** Number of pending LRU flush * LRU_FLUSH + FLUSH_LIST_ACTIVE flag. + Protected by flush_list_mutex. */ unsigned page_cleaner_status; + + /** Whether the page cleaner is sleeping due to being idle. + Writes occur under flush_list_mutex; reads are lock-free (used by + the early-return in buf_flush_ahead() on a busy cleaner). */ + Atomic_relaxed page_cleaner_idle_flag; + /** track server activity count for signaling idle flushing */ ulint last_activity_count; public: @@ -1580,19 +1585,19 @@ class buf_pool_t page_cleaner_status-= FLUSH_LIST_ACTIVE; } - /** @return whether the page cleaner must sleep due to being idle */ + /** @return whether the page cleaner must sleep due to being idle. + Lock-free read of page_cleaner_idle_flag; safe to call without + flush_list_mutex (used by the early-return in buf_flush_ahead()). */ bool page_cleaner_idle() const noexcept { - mysql_mutex_assert_owner(&flush_list_mutex); - return page_cleaner_status & PAGE_CLEANER_IDLE; + return page_cleaner_idle_flag; } /** @return whether the page cleaner may be initiating writes */ bool page_cleaner_active() const noexcept { mysql_mutex_assert_owner(&flush_list_mutex); - static_assert(PAGE_CLEANER_IDLE == 1, "efficiency"); - return page_cleaner_status > PAGE_CLEANER_IDLE; + return page_cleaner_status != 0; } /** Wake up the page cleaner if needed. @@ -1603,8 +1608,7 @@ class buf_pool_t void page_cleaner_set_idle(bool deep_sleep) noexcept { mysql_mutex_assert_owner(&flush_list_mutex); - page_cleaner_status= (page_cleaner_status & ~PAGE_CLEANER_IDLE) | - (PAGE_CLEANER_IDLE * deep_sleep); + page_cleaner_idle_flag= deep_sleep; } /** Update server last activity count */ diff --git a/storage/innobase/include/trx0purge.h b/storage/innobase/include/trx0purge.h index 58a396d94f8ab..4dc4516715d8d 100644 --- a/storage/innobase/include/trx0purge.h +++ b/storage/innobase/include/trx0purge.h @@ -40,9 +40,11 @@ struct TABLE; Remove the undo log segment from the rseg slot if it is too big for reuse. @param[in] trx transaction @param[in,out] undo undo log -@param[in,out] mtr mini-transaction */ +@param[in,out] mtr mini-transaction +@param[in] end transaction serialisation number */ void -trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr); +trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr, + trx_id_t end); /** Remove unnecessary history data from rollback segments. NOTE that when this diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index c619710f3ab54..929afdf8e0860 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -340,14 +340,6 @@ struct rw_trx_hash_element_t trx_id_t id; /* lf_hash_init() relies on this to be first in the struct */ - - /** - Transaction serialization number. - - Assigned shortly before the transaction is moved to COMMITTED_IN_MEMORY - state. Initially set to TRX_ID_MAX. - */ - Atomic_counter no; trx_t *trx; srw_mutex mutex; }; @@ -443,7 +435,6 @@ class rw_trx_hash_t ut_ad(element->trx == 0); element->trx= trx; element->id= trx->id; - element->no= TRX_ID_MAX; trx->rw_trx_hash_element= element; } @@ -512,7 +503,6 @@ class rw_trx_hash_t if (element->trx) validate_element(element->trx); element->mutex.wr_unlock(); - ut_ad(element->id < element->no); return arg->action(element, arg->argument); } #endif @@ -849,6 +839,130 @@ class thread_safe_trx_ilist_t alignas(CPU_LEVEL1_DCACHE_LINESIZE) ilist trx_list; }; +/** + Active read-write transaction identifiers and serialisation numbers container. + + Unlike rw_trx_hash_t, which is optimized for direct lookup, this + structure is optimized for compact storage and traversal of active + transactions by MVCC read view construction. + + The vector may contain empty slots corresponding to idle or read-only + transactions that currently do not own an active read-write trx_id. + Such slots are skipped during traversal. +*/ +class rw_trx_vector +{ + struct rw_trx_id + { + Atomic_relaxed id{TRX_ID_MAX}; + Atomic_relaxed no{TRX_ID_MAX}; + }; + alignas(CPU_LEVEL1_DCACHE_LINESIZE) + std::vector> + ids{ut_allocator(mem_key_trx_sys_t_rw_trx_ids)}; + std::vector> + trxs{ut_allocator(mem_key_trx_sys_t_rw_trx_ids)}; + alignas(CPU_LEVEL1_DCACHE_LINESIZE) mutable srw_spin_lock_low latch; + +public: + template + trx_id_t assign_new_trx_no(const trx_t *trx, Functor1 get_new_trx_id, + Functor2 refresh_rw_trx_hash_version) noexcept + { + trx_id_t no; + latch.rd_lock(); + ut_ad(trx->rw_trx_ids_slot < ids.size()); + ut_ad(trxs[trx->rw_trx_ids_slot] == trx); + ut_ad(ids[trx->rw_trx_ids_slot].id == trx->id); + ut_ad(ids[trx->rw_trx_ids_slot].no == TRX_ID_MAX); + ids[trx->rw_trx_ids_slot].no= no= get_new_trx_id(); + refresh_rw_trx_hash_version(); + latch.rd_unlock(); + return no; + } + trx_id_t snapshot_ids(trx_ids_t &view_ids, + const trx_id_t max_trx_id) const noexcept + { + trx_id_t min_trx_no{max_trx_id}; + view_ids.clear(); + latch.rd_lock(); + view_ids.reserve(ids.size()); + for (const auto &it : ids) + { + trx_id_t id{it.id}; + if (id < max_trx_id) + { + view_ids.push_back(id); + const trx_id_t no{it.no}; + if (no < min_trx_no) + min_trx_no= no; + } + } + latch.rd_unlock(); + return min_trx_no; + } + template + void register_rw(const trx_t *trx, Functor1 get_new_trx_id, + Functor2 refresh_rw_trx_hash_version) noexcept + { + latch.rd_lock(); + ut_ad(trx->rw_trx_ids_slot < ids.size()); + ut_ad(trxs[trx->rw_trx_ids_slot] == trx); + ut_ad(ids[trx->rw_trx_ids_slot].id == TRX_ID_MAX); + ut_ad(ids[trx->rw_trx_ids_slot].no == TRX_ID_MAX); + ids[trx->rw_trx_ids_slot].id= get_new_trx_id(); + refresh_rw_trx_hash_version(); + latch.rd_unlock(); + } + void deregister_rw(const trx_t *trx) noexcept + { + latch.rd_lock(); + ut_ad(trx->rw_trx_ids_slot < ids.size()); + rw_trx_id &slot= ids[trx->rw_trx_ids_slot]; + ut_ad(trxs[trx->rw_trx_ids_slot] == trx); + ut_ad(slot.id == trx->id); + slot.id= TRX_ID_MAX; + slot.no= TRX_ID_MAX; + latch.rd_unlock(); + } + void register_trx(trx_t *trx) noexcept + { + ut_ad(trx->rw_trx_ids_slot == std::numeric_limits::max()); + latch.wr_lock(); + trx->rw_trx_ids_slot= static_cast(ids.size()); + ids.emplace_back(); + trxs.emplace_back(trx); + latch.wr_unlock(); + } + void deregister_trx(trx_t *trx) noexcept + { + latch.wr_lock(); + ut_ad(trx->rw_trx_ids_slot < ids.size()); + ut_ad(trxs[trx->rw_trx_ids_slot] == trx); + if (trx->rw_trx_ids_slot + 1 < ids.size()) + { + trx_t *move_trx= trxs.back(); + ids[trx->rw_trx_ids_slot]= std::move(ids.back()); + trxs[trx->rw_trx_ids_slot]= std::move(trxs.back()); + move_trx->rw_trx_ids_slot= trx->rw_trx_ids_slot; + } + ids.pop_back(); + trxs.pop_back(); + latch.wr_unlock(); + ut_d(trx->rw_trx_ids_slot= std::numeric_limits::max()); + } + void create() noexcept + { + ut_ad(ids.size() == 0); + latch.init(); + } + void destroy() noexcept + { + ut_ad(ids.size() == 0); + latch.destroy(); + } +}; + /** The transaction system central memory data structure. */ class trx_sys_t { @@ -875,6 +989,15 @@ class trx_sys_t /** False if there is no undo log to purge or rollback */ bool undo_log_nonempty; + + /** + Collection of active read-write transaction identifiers and serialization + numbers used for MVCC snapshot creation. + + This complements rw_trx_hash with a traversal-friendly representation + optimized for collecting active transaction ids. + */ + rw_trx_vector rw_trx_ids; public: /** List of all transactions. */ thread_safe_trx_ilist_t trx_list; @@ -1014,7 +1137,7 @@ class trx_sys_t next call to trx_sys.get_new_trx_id() */ - trx_id_t get_max_trx_id() + trx_id_t get_max_trx_id() const noexcept { return m_max_trx_id; } @@ -1037,7 +1160,7 @@ class trx_sys_t Allocates and assigns new transaction serialisation number. There's a gap between m_max_trx_id increment and transaction serialisation - number becoming visible through rw_trx_hash. While we're in this gap + number becoming visible through rw_trx_ids. While we're in this gap concurrent thread may come and do MVCC snapshot without seeing allocated but not yet assigned serialisation number. Then at some point purge thread may clone this view. As a result it won't see newly allocated serialisation @@ -1047,58 +1170,43 @@ class trx_sys_t m_rw_trx_hash_version is intended to solve this problem. MVCC snapshot has to wait until m_max_trx_id == m_rw_trx_hash_version, which effectively means that all transaction serialisation numbers up to m_max_trx_id are - available through rw_trx_hash. + available through rw_trx_ids. We rely on refresh_rw_trx_hash_version() to issue RELEASE memory barrier so - that m_rw_trx_hash_version increment happens after - trx->rw_trx_hash_element->no becomes visible through rw_trx_hash. + that m_rw_trx_hash_version increment happens after transaction serialisation + number becomes visible through rw_trx_ids. @param trx transaction */ - void assign_new_trx_no(trx_t *trx) + trx_id_t assign_new_trx_no(trx_t *trx) { - trx->rw_trx_hash_element->no= get_new_trx_id_no_refresh(); - refresh_rw_trx_hash_version(); + return rw_trx_ids.assign_new_trx_no(trx, + [this](){ return get_new_trx_id_no_refresh(); }, + [this](){ refresh_rw_trx_hash_version(); }); } /** Takes MVCC snapshot. - To reduce malloc probablility we reserve rw_trx_hash.size() + 32 elements - in ids. - For details about get_rw_trx_hash_version() != get_max_trx_id() spin @sa register_rw() and @sa assign_new_trx_no(). We rely on get_rw_trx_hash_version() to issue ACQUIRE memory barrier so - that loading of m_rw_trx_hash_version happens before accessing rw_trx_hash. - - To optimise snapshot creation rw_trx_hash.iterate() is being used instead - of rw_trx_hash.iterate_no_dups(). It means that some transaction - identifiers may appear multiple times in ids. + that loading of m_rw_trx_hash_version happens before accessing rw_trx_ids. - @param[in,out] caller_trx used to get access to rw_trx_hash_pins @param[out] ids array to store registered transaction identifiers @param[out] max_trx_id variable to store m_max_trx_id value - @param[out] mix_trx_no variable to store min(no) value + + @return min(no) */ - void snapshot_ids(trx_t *caller_trx, trx_ids_t *ids, trx_id_t *max_trx_id, - trx_id_t *min_trx_no) + trx_id_t snapshot_ids(trx_ids_t &ids, trx_id_t &max_trx_id) const noexcept { - snapshot_ids_arg arg(ids); - - while ((arg.m_id= get_rw_trx_hash_version()) != get_max_trx_id()) + while ((max_trx_id= get_rw_trx_hash_version()) != get_max_trx_id()) ut_delay(1); - arg.m_no= arg.m_id; - ids->clear(); - ids->reserve(rw_trx_hash.size() + 32); - rw_trx_hash.iterate(caller_trx, copy_one_id, &arg); - - *max_trx_id= arg.m_id; - *min_trx_no= arg.m_no; + return rw_trx_ids.snapshot_ids(ids, max_trx_id); } @@ -1149,7 +1257,7 @@ class trx_sys_t Transaction becomes visible to MVCC. There's a gap between m_max_trx_id increment and transaction becoming - visible through rw_trx_hash. While we're in this gap concurrent thread may + visible through rw_trx_ids. While we're in this gap concurrent thread may come and do MVCC snapshot. As a result concurrent read view will be able to observe records owned by this transaction even before it was committed. @@ -1165,21 +1273,32 @@ class trx_sys_t void register_rw(trx_t *trx) { - trx->id= get_new_trx_id_no_refresh(); + rw_trx_ids.register_rw(trx, + [this, trx](){ return trx->id= get_new_trx_id_no_refresh(); }, + [this](){ refresh_rw_trx_hash_version(); }); rw_trx_hash.insert(trx); - refresh_rw_trx_hash_version(); + } + + + void resurrect_rw(trx_t *trx) + { + rw_trx_ids.register_rw(trx, [trx](){ return trx->id; }, [](){}); + rw_trx_hash.insert(trx); + rw_trx_hash.put_pins(trx); } /** Deregisters read-write transaction. - Transaction is removed from rw_trx_hash, which releases all implicit locks. - MVCC snapshot won't see this transaction anymore. + After this call the transaction is no longer visible as active to MVCC read + views created subsequently, and all implicit locks held by the transaction + have been released. */ - void deregister_rw(trx_t *trx) + void deregister_rw(trx_t *trx) noexcept { + rw_trx_ids.deregister_rw(trx); rw_trx_hash.erase(trx); } @@ -1204,6 +1323,7 @@ class trx_sys_t void register_trx(trx_t *trx) { trx_list.push_front(*trx); + rw_trx_ids.register_trx(trx); } @@ -1214,6 +1334,7 @@ class trx_sys_t */ void deregister_trx(trx_t *trx) { + rw_trx_ids.deregister_trx(trx); trx_list.remove(*trx); } @@ -1266,33 +1387,8 @@ class trx_sys_t private: static my_bool find_same_or_older_callback(void *el, void *i) noexcept; - - struct snapshot_ids_arg - { - snapshot_ids_arg(trx_ids_t *ids): m_ids(ids) {} - trx_ids_t *m_ids; - trx_id_t m_id; - trx_id_t m_no; - }; - - - static my_bool copy_one_id(void* el, void *a) - { - auto element= static_cast(el); - auto arg= static_cast(a); - if (element->id < arg->m_id) - { - trx_id_t no= element->no; - arg->m_ids->push_back(element->id); - if (no < arg->m_no) - arg->m_no= no; - } - return 0; - } - - /** Getter for m_rw_trx_hash_version, must issue ACQUIRE memory barrier. */ - trx_id_t get_rw_trx_hash_version() + trx_id_t get_rw_trx_hash_version() const noexcept { return m_rw_trx_hash_version.load(std::memory_order_acquire); } diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 751b45d32f968..90f86d46eb332 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -629,6 +629,8 @@ struct trx_t : ilist_node<> public: + /** trx_sys.rw_trx_ids index, protected by trx_sys.rw_trx_ids.latch */ + uint32_t rw_trx_ids_slot; /** Transaction identifier (0 if no locks were acquired). Set by trx_sys_t::register_rw() or trx_resurrect() before the transaction is added to trx_sys.rw_trx_hash. diff --git a/storage/innobase/include/ut0new.h b/storage/innobase/include/ut0new.h index 398dd0dcc9ecd..d234110accb66 100644 --- a/storage/innobase/include/ut0new.h +++ b/storage/innobase/include/ut0new.h @@ -173,6 +173,7 @@ extern PSI_memory_key mem_key_other; extern PSI_memory_key mem_key_row_log_buf; extern PSI_memory_key mem_key_row_merge_sort; extern PSI_memory_key mem_key_std; +extern PSI_memory_key mem_key_trx_sys_t_rw_trx_ids; /** Setup the internal objects needed for UT_NEW() to operate. This must be called before the first call to UT_NEW(). */ diff --git a/storage/innobase/read/read0read.cc b/storage/innobase/read/read0read.cc index 46d58326edfcf..2d12fb2777f43 100644 --- a/storage/innobase/read/read0read.cc +++ b/storage/innobase/read/read0read.cc @@ -172,7 +172,7 @@ For details see: row_undo_mod_sec_is_unsafe() and row_purge_poss_sec() */ inline void ReadViewBase::snapshot(trx_t *trx) { - trx_sys.snapshot_ids(trx, &m_ids, &m_low_limit_id, &m_low_limit_no); + m_low_limit_no= trx_sys.snapshot_ids(m_ids, m_low_limit_id); if (m_ids.empty()) { m_up_limit_id= m_low_limit_id; diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 06913fd7e555f..74262b55c1545 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -157,12 +157,14 @@ bool purge_sys_t::is_purgeable(trx_id_t trx_id) const noexcept Remove the undo log segment from the rseg slot if it is too big for reuse. @param[in] trx transaction @param[in,out] undo undo log -@param[in,out] mtr mini-transaction */ +@param[in,out] mtr mini-transaction +@param[in] end transaction serialisation number */ void -trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) +trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr, + trx_id_t end) { DBUG_PRINT("trx", ("commit(" TRX_ID_FMT "," TRX_ID_FMT ")", - trx->id, trx_id_t{trx->rw_trx_hash_element->no})); + trx->id, end)); ut_ad(undo->id < TRX_RSEG_N_SLOTS); ut_ad(undo == trx->rsegs.m_redo.undo); trx_rseg_t *rseg= trx->rsegs.m_redo.rseg; @@ -263,7 +265,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) mtr->write<2>(*undo_page, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + undo_page->page.frame, undo_state); mtr->write<8,mtr_t::MAYBE_NOP>(*undo_page, undo_header + TRX_UNDO_TRX_NO, - trx->rw_trx_hash_element->no); + end); } /** Free an undo log segment. diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 2f2265a3df1fd..57e463d25057a 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -168,6 +168,7 @@ void trx_sys_t::create() m_initialised= true; trx_list.create(); rw_trx_hash.init(); + rw_trx_ids.create(); for (auto &rseg : temp_rsegs) rseg.init(nullptr, FIL_NULL); for (auto &rseg : rseg_array) @@ -361,6 +362,7 @@ trx_sys_t::close() } rw_trx_hash.destroy(); + rw_trx_ids.destroy(); /* There can't be any active transactions. */ for (auto& rseg : temp_rsegs) rseg.destroy(); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 7b5e191a35dfb..2abdecb4bd60d 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -185,6 +185,7 @@ struct TrxFactory { new(&trx->read_view) ReadView(); trx->rw_trx_hash_pins = 0; + ut_d(trx->rw_trx_ids_slot = std::numeric_limits::max()); trx_init(trx); trx->dict_operation_lock_mode = false; @@ -407,6 +408,7 @@ void trx_t::free() noexcept MEM_NOACCESS(&skip_lock_inheritance_and_n_ref, sizeof skip_lock_inheritance_and_n_ref); /* do not poison mutex */ + MEM_NOACCESS(&rw_trx_ids_slot, sizeof rw_trx_ids_slot); MEM_NOACCESS(&id, sizeof id); MEM_NOACCESS(&max_inactive_id, sizeof id); MEM_NOACCESS(&state, sizeof state); @@ -700,8 +702,7 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg, trx->start_time_micro= start_time_micro; trx->dict_operation= undo->dict_operation; - trx_sys.rw_trx_hash.insert(trx); - trx_sys.rw_trx_hash.put_pins(trx); + trx_sys.resurrect_rw(trx); if (trx_state_eq(trx, TRX_STATE_ACTIVE)) *rows_to_undo+= trx->undo_no; return trx_resurrect_table_locks(trx, *undo); @@ -1140,6 +1141,7 @@ inline void trx_t::write_serialisation_history(mtr_t *mtr) trx_undo_t *&undo= rsegs.m_redo.undo; if (UNIV_LIKELY(undo != nullptr)) { + trx_id_t end; MONITOR_INC(MONITOR_TRX_COMMIT_UNDO); /* We have to hold exclusive rseg->latch because undo log headers have @@ -1166,8 +1168,7 @@ inline void trx_t::write_serialisation_history(mtr_t *mtr) thread can also fetch redo log records from rseg with greater last commit number before rseg with lesser one. */ purge_sys.queue_lock(); - trx_sys.assign_new_trx_no(this); - const trx_id_t end{rw_trx_hash_element->no}; + end= trx_sys.assign_new_trx_no(this); rseg->last_page_no= undo->hdr_page_no; /* end cannot be less than anything in rseg. User threads only produce events when a rollback segment is empty. */ @@ -1176,12 +1177,12 @@ inline void trx_t::write_serialisation_history(mtr_t *mtr) purge_sys.queue_unlock(); } else - trx_sys.assign_new_trx_no(this); + end= trx_sys.assign_new_trx_no(this); UT_LIST_REMOVE(rseg->undo_list, undo); /* Change the undo log segment state from TRX_UNDO_ACTIVE, to define the transaction as committed in the file based domain, at mtr->commit_lsn() obtained in mtr->commit() below. */ - trx_purge_add_undo_to_history(this, undo, mtr); + trx_purge_add_undo_to_history(this, undo, mtr, end); done: rseg->release(); rseg->latch.wr_unlock(); diff --git a/storage/innobase/ut/ut0new.cc b/storage/innobase/ut/ut0new.cc index a3ce1bdf3c767..dc0cad90c845a 100644 --- a/storage/innobase/ut/ut0new.cc +++ b/storage/innobase/ut/ut0new.cc @@ -46,6 +46,7 @@ PSI_memory_key mem_key_other; PSI_memory_key mem_key_row_log_buf; PSI_memory_key mem_key_row_merge_sort; PSI_memory_key mem_key_std; +PSI_memory_key mem_key_trx_sys_t_rw_trx_ids; #ifdef UNIV_PFS_MEMORY @@ -73,6 +74,7 @@ static PSI_memory_info pfs_info[] = { {&mem_key_row_log_buf, "row_log_buf", 0}, {&mem_key_row_merge_sort, "row_merge_sort", 0}, {&mem_key_std, "std", 0}, + {&mem_key_trx_sys_t_rw_trx_ids, "trx_sys_t::rw_trx_ids", 0}, }; static const int NKEYS = static_castUT_ARR_SIZE(auto_event_names)-1; diff --git a/storage/mroonga/vendor/groonga/lib/expr.c b/storage/mroonga/vendor/groonga/lib/expr.c index de3c080d6cd54..559a21f6b9882 100644 --- a/storage/mroonga/vendor/groonga/lib/expr.c +++ b/storage/mroonga/vendor/groonga/lib/expr.c @@ -441,7 +441,7 @@ grn_expr_unpack(grn_ctx *ctx, const uint8_t *p, const uint8_t *pe, grn_obj *expr break; case GRN_EXPR_PACK_TYPE_VARIABLE : { - uint32_t offset; + uint32_t offset __attribute__((unused)); GRN_B_DEC(offset, p); code->value = &e->vars[i].value; } @@ -2663,7 +2663,7 @@ grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs) break; case GRN_OP_POP : { - grn_obj *obj; + grn_obj *obj __attribute__((unused)); POP1(obj); code++; } @@ -3535,7 +3535,10 @@ grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs) { int r; grn_obj *value; - int64_t ln0, la0, ln1, la1, ln2, la2, ln3, la3; + int64_t ln0, la0, ln2, la2, ln3, la3; + int64_t ln1 __attribute__((unused)); + int64_t la1 __attribute__((unused)); + POP1(value); ln0 = GRN_INT32_VALUE(value); POP1(value); @@ -6025,7 +6028,7 @@ grn_table_select_index_not_equal(grn_ctx *ctx, processed = GRN_TRUE; } else { uint32_t sid; - int32_t weight; + int32_t weight __attribute__((unused)); grn_ii *ii = (grn_ii *)index; grn_ii_cursor *ii_cursor; diff --git a/storage/mroonga/vendor/groonga/lib/grn_ecmascript.c b/storage/mroonga/vendor/groonga/lib/grn_ecmascript.c index cfc8fd2dd7410..0db5474452957 100644 --- a/storage/mroonga/vendor/groonga/lib/grn_ecmascript.c +++ b/storage/mroonga/vendor/groonga/lib/grn_ecmascript.c @@ -1474,40 +1474,40 @@ static void yy_reduce( break; case 4: /* query ::= query NEGATIVE query_element */ { - int weight; + int weight __attribute__((unused)); GRN_INT32_POP(&efsi->weight_stack, weight); grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_ADJUST, 2); } break; case 5: /* query_element ::= ADJUST query_element */ { - int weight; + int weight __attribute__((unused)); GRN_INT32_POP(&efsi->weight_stack, weight); } break; case 6: /* query_element ::= RELATIVE_OP query_element */ { - int mode; + int mode __attribute__((unused)); GRN_INT32_POP(&efsi->mode_stack, mode); } break; case 7: /* query_element ::= IDENTIFIER RELATIVE_OP query_element */ { int mode; - grn_obj *c; + grn_obj *c __attribute__((unused)); GRN_PTR_POP(&efsi->column_stack, c); GRN_INT32_POP(&efsi->mode_stack, mode); switch (mode) { case GRN_OP_NEAR : case GRN_OP_NEAR2 : { - int max_interval; + int max_interval __attribute__((unused)); GRN_INT32_POP(&efsi->max_interval_stack, max_interval); } break; case GRN_OP_SIMILAR : { - int similarity_threshold; + int similarity_threshold __attribute__((unused)); GRN_INT32_POP(&efsi->similarity_threshold_stack, similarity_threshold); } break; diff --git a/storage/mroonga/vendor/groonga/lib/grn_io.h b/storage/mroonga/vendor/groonga/lib/grn_io.h index bc5ecf7fa1e9b..0c9e50f720295 100644 --- a/storage/mroonga/vendor/groonga/lib/grn_io.h +++ b/storage/mroonga/vendor/groonga/lib/grn_io.h @@ -276,7 +276,8 @@ void grn_io_seg_map_(grn_ctx *ctx, grn_io *io, uint32_t segno, grn_io_mapinfo *i #define GRN_IO_SEG_UNREF(io,segno) do {\ if (GRN_IO_EXPIRE_SEGMENT ==\ (io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {\ - uint32_t nref, *pnref = &(io)->maps[segno].nref;\ + uint32_t nref __attribute__((unused)); \ + uint32_t *pnref = &(io)->maps[segno].nref; \ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\ }\ } while (0)