diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 308e46a2f76..4f7c727594b 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -664,6 +664,108 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, DBUG_RETURN(result); } +#ifdef WITH_WSREP +/* + * If brute force applier would need to wait for a thr lock, + * it needs to make sure that it will get the lock without (too much) + * delay. + * We identify here the owners of blocking locks and ask them to + * abort. We then put our lock request in the first place in the + * wait queue. When lock holders abort (one by one) the lock release + * algorithm should grant the lock to us. We rely on this and proceed + * to wait_for_locks(). + * wsrep_break_locks() should be called in all the cases, where lock + * wait would happen. + * + * TODO: current implementation might not cover all possible lock wait + * situations. This needs an review still. + * TODO: lock release, might favor some other lock (instead our bf). + * This needs an condition to check for bf locks first. + * TODO: we still have a debug fprintf, this should be removed + */ +static inline my_bool +wsrep_break_lock( + THR_LOCK_DATA *data, struct st_lock_list *lock_queue1, + struct st_lock_list *lock_queue2, struct st_lock_list *wait_queue) +{ + if (wsrep_on(data->owner->mysql_thd) && + wsrep_thd_is_brute_force && + wsrep_thd_is_brute_force(data->owner->mysql_thd)) + { + THR_LOCK_DATA *holder; + + /* if locking session conversion to transaction has been enabled, + we know that this conflicting lock must be read lock and furthermore, + lock holder is read-only. It is safe to wait for him. + */ +#ifdef TODO + if (wsrep_convert_LOCK_to_trx && + (THD*)(data->owner->mysql_thd)->in_lock_tables) + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock read lock untouched\n"); + return FALSE; + } +#endif + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock aborting locks\n"); + + /* aborting lock holder(s) here */ + for (holder=(lock_queue1) ? lock_queue1->data : NULL; + holder; + holder=holder->next) + { + if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd)) + { + wsrep_abort_thd(data->owner->mysql_thd, + holder->owner->mysql_thd, FALSE); + } + else + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); + return FALSE; + } + } + for (holder=(lock_queue2) ? lock_queue2->data : NULL; + holder; + holder=holder->next) + { + if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd)) + { + wsrep_abort_thd(data->owner->mysql_thd, + holder->owner->mysql_thd, FALSE); + } + else + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); + return FALSE; + } + } + + /* Add our lock to the head of the wait queue */ + if (*(wait_queue->last)==wait_queue->data) + { + wait_queue->last=&data->next; + assert(wait_queue->data==0); + } + else + { + assert(wait_queue->data!=0); + wait_queue->data->prev=&data->next; + } + data->next=wait_queue->data; + data->prev=&wait_queue->data; + wait_queue->data=data; + data->cond=get_cond(); + + statistic_increment(locks_immediate,&THR_LOCK_lock); + return TRUE; + } + return FALSE; +} +#endif static enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) @@ -672,6 +774,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) enum enum_thr_lock_result result= THR_LOCK_SUCCESS; struct st_lock_list *wait_queue; enum thr_lock_type lock_type= data->type; +#ifdef WITH_WSREP + my_bool wsrep_lock_inserted= FALSE; +#endif MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */ DBUG_ENTER("thr_lock"); @@ -741,6 +846,14 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) } if (lock->write.data->type == TL_WRITE_ONLY) { +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->read_wait)) + { + wsrep_lock_inserted= TRUE; + goto wsrep_read_wait; + } +#endif + /* We are not allowed to get a READ lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ @@ -768,6 +881,14 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) lock but a high priority write waiting in the write_wait queue. In the latter case we should yield the lock to the writer. */ +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->read_wait)) + { + wsrep_lock_inserted= TRUE; + } + wsrep_read_wait: +#endif + wait_queue= &lock->read_wait; } else /* Request for WRITE lock */ @@ -776,12 +897,25 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) { if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY) { +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + { + wsrep_lock_inserted=TRUE; + goto wsrep_write_wait; + } +#endif data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } if (lock->write.data || lock->read.data) { +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + { + goto end; + } +#endif /* Add delayed write lock to write_wait queue, and return at once */ (*lock->write_wait.last)=data; data->prev=lock->write_wait.last; @@ -806,6 +940,13 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) /* Allow lock owner to bypass TL_WRITE_ONLY. */ if (!thr_lock_owner_equal(data->owner, lock->write.data->owner)) { +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + { + wsrep_lock_inserted=TRUE; + goto wsrep_write_wait; + } +#endif /* We are not allowed to get a lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ @@ -909,9 +1050,22 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d", lock->read.data->owner->thread_id, data->type)); } +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, NULL, &lock->write_wait)) + { + wsrep_lock_inserted= TRUE; + } + wsrep_write_wait: + +#endif + wait_queue= &lock->write_wait; } /* Can't get lock yet; Wait for it */ +#ifdef WITH_WSREP + if (wsrep_on(data->owner->mysql_thd) && wsrep_lock_inserted) + DBUG_RETURN(wait_for_lock(wait_queue, data, 1, lock_wait_timeout)); +#endif result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout); MYSQL_END_TABLE_LOCK_WAIT(locker); DBUG_RETURN(result); @@ -1174,109 +1328,6 @@ static void sort_locks(THR_LOCK_DATA **data,uint count) } } -#ifdef WITH_WSREP -/* - * If brute force applier would need to wait for a thr lock, - * it needs to make sure that it will get the lock without (too much) - * delay. - * We identify here the owners of blocking locks and ask them to - * abort. We then put our lock request in the first place in the - * wait queue. When lock holders abort (one by one) the lock release - * algorithm should grant the lock to us. We rely on this and proceed - * to wait_for_locks(). - * wsrep_break_locks() should be called in all the cases, where lock - * wait would happen. - * - * TODO: current implementation might not cover all possible lock wait - * situations. This needs an review still. - * TODO: lock release, might favor some other lock (instead our bf). - * This needs an condition to check for bf locks first. - * TODO: we still have a debug fprintf, this should be removed - */ -static inline my_bool -wsrep_break_lock( - THR_LOCK_DATA *data, struct st_lock_list *lock_queue1, - struct st_lock_list *lock_queue2, struct st_lock_list *wait_queue) -{ - if (wsrep_on(data->owner->mysql_thd) && - wsrep_thd_is_brute_force && - wsrep_thd_is_brute_force(data->owner->mysql_thd)) - { - THR_LOCK_DATA *holder; - - /* if locking session conversion to transaction has been enabled, - we know that this conflicting lock must be read lock and furthermore, - lock holder is read-only. It is safe to wait for him. - */ -#ifdef TODO - if (wsrep_convert_LOCK_to_trx && - (THD*)(data->owner->mysql_thd)->in_lock_tables) - { - if (wsrep_debug) - fprintf(stderr,"WSREP wsrep_break_lock read lock untouched\n"); - return FALSE; - } -#endif - if (wsrep_debug) - fprintf(stderr,"WSREP wsrep_break_lock aborting locks\n"); - - /* aborting lock holder(s) here */ - for (holder=(lock_queue1) ? lock_queue1->data : NULL; - holder; - holder=holder->next) - { - if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd)) - { - wsrep_abort_thd(data->owner->mysql_thd, - holder->owner->mysql_thd, FALSE); - } - else - { - if (wsrep_debug) - fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); - return FALSE; - } - } - for (holder=(lock_queue2) ? lock_queue2->data : NULL; - holder; - holder=holder->next) - { - if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd)) - { - wsrep_abort_thd(data->owner->mysql_thd, - holder->owner->mysql_thd, FALSE); - } - else - { - if (wsrep_debug) - fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); - return FALSE; - } - } - - /* Add our lock to the head of the wait queue */ - if (*(wait_queue->last)==wait_queue->data) - { - wait_queue->last=&data->next; - assert(wait_queue->data==0); - } - else - { - assert(wait_queue->data!=0); - wait_queue->data->prev=&data->next; - } - data->next=wait_queue->data; - data->prev=&wait_queue->data; - wait_queue->data=data; - data->cond=get_cond(); - - statistic_increment(locks_immediate,&THR_LOCK_lock); - return TRUE; - } - return FALSE; -} -#endif - enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_INFO *owner, ulong lock_wait_timeout) diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 7db2a5605e1..113c3236fab 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -18,6 +18,8 @@ niceness=0 nowatch=0 mysqld_ld_preload= mysqld_ld_library_path= +flush_caches=0 +numa_interleave=0 # Initial logging status: error log is not open, and not using syslog logging=init @@ -85,6 +87,10 @@ Usage: $0 [OPTIONS] --syslog Log messages to syslog with 'logger' --skip-syslog Log messages to error log (default) --syslog-tag=TAG Pass -t "mysqld-TAG" to 'logger' + --flush-caches Flush and purge buffers/caches before + starting the server + --numa-interleave Run mysqld with its memory interleaved + on all NUMA nodes All other options are passed to the mysqld program. @@ -312,6 +318,8 @@ parse_arguments() { --syslog-tag=*) syslog_tag="$val" ;; --timezone=*) TZ="$val"; export TZ; ;; --wsrep[-_]urls=*) wsrep_urls="$val"; ;; + --flush-caches) flush_caches=1 ;; + --numa-interleave) numa_interleave=1 ;; --wsrep[-_]provider=*) if test -n "$val" && test "$val" != "none" then @@ -834,6 +842,40 @@ mysqld daemon not started" fi fi +# Flush and purge buffers/caches. +# + +if @TARGET_LINUX@ && test $flush_caches -eq 1 +then + # Locate sync, ensure it exists. + if ! my_which sync > /dev/null 2>&1 + then + log_error "sync command not found, required for --flush-caches" + exit 1 + # Flush file system buffers. + elif ! sync + then + # Huh, the sync() function is always successful... + log_error "sync failed, check if sync is properly installed" + fi + + # Locate sysctl, ensure it exists. + if ! my_which sysctl > /dev/null 2>&1 + then + log_error "sysctl command not found, required for --flush-caches" + exit 1 + # Purge page cache, dentries and inodes. + elif ! sysctl -q -w vm.drop_caches=3 + then + log_error "sysctl failed, check the error message for details" + exit 1 + fi +elif test $flush_caches -eq 1 +then + log_error "--flush-caches is not supported on this platform" + exit 1 +fi + # # Uncomment the following lines if you want all tables to be automatically # checked and repaired during startup. You should add sensible key_buffer @@ -854,6 +896,32 @@ fi cmd="`mysqld_ld_preload_text`$NOHUP_NICENESS" +# +# Set mysqld's memory interleave policy. +# + +if @TARGET_LINUX@ && test $numa_interleave -eq 1 +then + # Locate numactl, ensure it exists. + if ! my_which numactl > /dev/null 2>&1 + then + log_error "numactl command not found, required for --numa-interleave" + exit 1 + # Attempt to run a command, ensure it works. + elif ! numactl --interleave=all true + then + log_error "numactl failed, check if numactl is properly installed" + fi + + # Launch mysqld with numactl. + cmd="$cmd numactl --interleave=all" +elif test $numa_interleave -eq 1 +then + log_error "--numa-interleave is not supported on this platform" + exit 1 +fi + + for i in "$ledir/$MYSQLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ "--datadir=$DATADIR" "--plugin-dir=$plugin_dir" "$USER_OPTION" do diff --git a/sql/events.cc b/sql/events.cc index 96c4effe3d9..7df8d19644d 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -1167,6 +1167,7 @@ end: close_mysql_tables(thd); DBUG_RETURN(ret); } + #ifdef WITH_WSREP int wsrep_create_event_query(THD *thd, uchar** buf, uint* buf_len) { diff --git a/sql/handler.cc b/sql/handler.cc index e20afb5798f..dd297740c7d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1387,7 +1387,6 @@ int ha_commit_trans(THD *thd, bool all) err= ht->prepare(ht, thd, all); status_var_increment(thd->status_var.ha_prepare_count); if (err) - { #ifdef WITH_WSREP if (WSREP(thd) && ht->db_type== DB_TYPE_WSREP) { @@ -1402,7 +1401,6 @@ int ha_commit_trans(THD *thd, bool all) /* not wsrep hton, bail to native mysql behavior */ #endif my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); - } if (err) goto err; diff --git a/sql/lock.cc b/sql/lock.cc index 99a53ebfe3b..62540bcb55a 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -320,7 +320,8 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) sql_lock->lock_count * sizeof(*sql_lock->locks)); #ifdef WITH_WSREP thd->lock_info.in_lock_tables= thd->in_lock_tables; -#endif /* Lock on the copied half of the lock data array. */ +#endif + /* Lock on the copied half of the lock data array. */ rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + sql_lock->lock_count, @@ -330,6 +331,12 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) (void) unlock_external(thd, sql_lock->table, sql_lock->table_count); end: +#ifdef WITH_WSREP + thd_proc_info(thd, "mysql_lock_tables(): unlocking tables II"); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ + if (thd->killed) { thd->send_kill_message(); diff --git a/sql/log_event.cc b/sql/log_event.cc index 3d2a499a2b7..4f4d88df739 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4340,6 +4340,21 @@ Query_log_event::do_shall_skip(Relay_log_info *rli) DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } } +#ifdef WITH_WSREP + else if (wsrep_mysql_replication_bundle && WSREP_ON && thd->wsrep_mysql_replicated > 0 && + (!strncasecmp(query , "BEGIN", 5) || !strncasecmp(query , "COMMIT", 6))) + { + if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) + { + WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated); + DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE); + } + else + { + thd->wsrep_mysql_replicated = 0; + } + } +#endif DBUG_RETURN(Log_event::do_shall_skip(rli)); } @@ -7014,6 +7029,20 @@ Xid_log_event::do_shall_skip(Relay_log_info *rli) thd->variables.option_bits&= ~OPTION_BEGIN; DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } +#ifdef WITH_WSREP + else if (wsrep_mysql_replication_bundle && WSREP_ON) + { + if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) + { + WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated); + DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE); + } + else + { + thd->wsrep_mysql_replicated = 0; + } + } +#endif DBUG_RETURN(Log_event::do_shall_skip(rli)); } #endif /* !MYSQL_CLIENT */ @@ -8038,6 +8067,14 @@ err: end_io_cache(&file); if (fd >= 0) mysql_file_close(fd, MYF(0)); +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "exit Create_file_log_event::do_apply_event()"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ return error != 0; } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -8208,6 +8245,14 @@ int Append_block_log_event::do_apply_event(Relay_log_info const *rli) err: if (fd >= 0) mysql_file_close(fd, MYF(0)); +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "exit Append_block_log_event::do_apply_event()"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ DBUG_RETURN(error); } #endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d2a3c028fd1..8a9e8db53fb 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4464,6 +4464,26 @@ static int init_thread_environment() rpl_init_gtid_slave_state(); #endif +#ifdef WITH_WSREP + mysql_mutex_init(key_LOCK_wsrep_ready, + &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL); + mysql_mutex_init(key_LOCK_wsrep_sst, + &LOCK_wsrep_sst, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL); + mysql_mutex_init(key_LOCK_wsrep_sst_init, + &LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL); + mysql_mutex_init(key_LOCK_wsrep_rollback, + &LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL); + mysql_mutex_init(key_LOCK_wsrep_replaying, + &LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL); + mysql_mutex_init(key_LOCK_wsrep_slave_threads, + &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST); +#endif + DBUG_RETURN(0); } @@ -5076,4687 +5096,4694 @@ static void create_shutdown_thread() #endif /* EMBEDDED_LIBRARY */ +#ifdef WITH_WSREP +typedef void (*wsrep_thd_processor_fun)(THD *); -#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) -static void handle_connections_methods() +pthread_handler_t start_wsrep_THD(void *arg) { - pthread_t hThread; - DBUG_ENTER("handle_connections_methods"); - if (hPipe == INVALID_HANDLE_VALUE && - (!have_tcpip || opt_disable_networking) && - !opt_enable_shared_memory) - { - sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS"); - unireg_abort(1); // Will not return - } + THD *thd; + wsrep_thd_processor_fun processor= (wsrep_thd_processor_fun)arg; - mysql_mutex_lock(&LOCK_thread_count); - mysql_cond_init(key_COND_handler_count, &COND_handler_count, NULL); - handler_count=0; - if (hPipe != INVALID_HANDLE_VALUE) - { - handler_count++; - if (mysql_thread_create(key_thread_handle_con_namedpipes, - &hThread, &connection_attrib, - handle_connections_namedpipes, 0)) - { - sql_print_warning("Can't create thread to handle named pipes"); - handler_count--; - } - } - if (have_tcpip && !opt_disable_networking) + if (my_thread_init()) { - handler_count++; - if (mysql_thread_create(key_thread_handle_con_sockets, - &hThread, &connection_attrib, - handle_connections_sockets_thread, 0)) - { - sql_print_warning("Can't create thread to handle TCP/IP"); - handler_count--; - } + WSREP_ERROR("Could not initialize thread"); + return(NULL); } -#ifdef HAVE_SMEM - if (opt_enable_shared_memory) + + if (!(thd= new THD(true))) { - handler_count++; - if (mysql_thread_create(key_thread_handle_con_sharedmem, - &hThread, &connection_attrib, - handle_connections_shared_memory, 0)) - { - sql_print_warning("Can't create thread to handle shared memory"); - handler_count--; - } + return(NULL); } -#endif + mysql_mutex_lock(&LOCK_thread_count); + thd->thread_id=thread_id++; - while (handler_count > 0) - mysql_cond_wait(&COND_handler_count, &LOCK_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); - DBUG_VOID_RETURN; -} + thd->real_id=pthread_self(); // Keep purify happy + thread_count++; + thread_created++; + threads.append(thd); -void decrement_handler_count() -{ - mysql_mutex_lock(&LOCK_thread_count); - handler_count--; - mysql_cond_signal(&COND_handler_count); - mysql_mutex_unlock(&LOCK_thread_count); - my_thread_end(); -} -#else -#define decrement_handler_count() -#endif /* defined(_WIN32) || defined(HAVE_SMEM) */ + my_net_init(&thd->net,(st_vio*) 0, MYF(0)); + DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id)); + thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer(); + (void) mysql_mutex_unlock(&LOCK_thread_count); -#ifndef EMBEDDED_LIBRARY -#ifndef DBUG_OFF -/* - Debugging helper function to keep the locale database - (see sql_locale.cc) and max_month_name_length and - max_day_name_length variable values in consistent state. -*/ -static void test_lc_time_sz() -{ - DBUG_ENTER("test_lc_time_sz"); - for (MY_LOCALE **loc= my_locales; *loc; loc++) + /* from bootstrap()... */ + thd->bootstrap=1; + thd->max_client_packet_length= thd->net.max_packet; + thd->security_ctx->master_access= ~(ulong)0; + + /* from handle_one_connection... */ + pthread_detach_this_thread(); + + mysql_thread_set_psi_id(thd->thread_id); + thd->thr_create_utime= microsecond_interval_timer(); + if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0)) { - uint max_month_len= 0; - uint max_day_len = 0; - for (const char **month= (*loc)->month_names->type_names; *month; month++) - { - set_if_bigger(max_month_len, - my_numchars_mb(&my_charset_utf8_general_ci, - *month, *month + strlen(*month))); - } - for (const char **day= (*loc)->day_names->type_names; *day; day++) - { - set_if_bigger(max_day_len, - my_numchars_mb(&my_charset_utf8_general_ci, - *day, *day + strlen(*day))); - } - if ((*loc)->max_month_name_length != max_month_len || - (*loc)->max_day_name_length != max_day_len) - { - DBUG_PRINT("Wrong max day name(or month name) length for locale:", - ("%s", (*loc)->name)); - DBUG_ASSERT(0); - } - } - DBUG_VOID_RETURN; -} -#endif//DBUG_OFF + close_connection(thd, ER_OUT_OF_RESOURCES, 1); + statistic_increment(aborted_connects,&LOCK_status); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + return(NULL); + } -#ifdef __WIN__ -int win_main(int argc, char **argv) -#else -int mysqld_main(int argc, char **argv) -#endif -{ +// /* - Perform basic thread library and malloc initialization, - to be able to read defaults files and parse options. + handle_one_connection() is normally the only way a thread would + start and would always be on the very high end of the stack , + therefore, the thread stack always starts at the address of the + first local variable of handle_one_connection, which is thd. We + need to know the start of the stack so that we could check for + stack overruns. */ - my_progname= argv[0]; - sf_leaking_memory= 1; // no safemalloc memory leak reports if we exit early - mysqld_server_started= mysqld_server_initialized= 0; + DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n", + (long long)thd->thread_id)); + /* now that we've called my_thread_init(), it is safe to call DBUG_* */ -#ifdef HAVE_NPTL - ld_assume_kernel_is_set= (getenv("LD_ASSUME_KERNEL") != 0); -#endif -#ifndef _WIN32 - // For windows, my_init() is called from the win specific mysqld_main - if (my_init()) // init my_sys library & pthreads + thd->thread_stack= (char*) &thd; + if (thd->store_globals()) { - fprintf(stderr, "my_init() failed."); - return 1; + close_connection(thd, ER_OUT_OF_RESOURCES, 1); + statistic_increment(aborted_connects,&LOCK_status); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + delete thd; + + return(NULL); } -#endif - orig_argc= argc; - orig_argv= argv; - my_getopt_use_args_separator= TRUE; - if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv)) - return 1; - my_getopt_use_args_separator= FALSE; - defaults_argc= argc; - defaults_argv= argv; - remaining_argc= argc; - remaining_argv= argv; + thd->system_thread= SYSTEM_THREAD_SLAVE_SQL; + thd->security_ctx->skip_grants(); - /* Must be initialized early for comparison of options name */ - system_charset_info= &my_charset_utf8_general_ci; + /* handle_one_connection() again... */ + //thd->version= refresh_version; + thd->proc_info= 0; + thd->set_command(COM_SLEEP); + thd->set_time(); + thd->init_for_queries(); - sys_var_init(); + mysql_mutex_lock(&LOCK_connection_count); + ++connection_count; + mysql_mutex_unlock(&LOCK_connection_count); -#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE - /* - Initialize the array of performance schema instrument configurations. - */ - init_pfs_instrument_array(); -#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ - /* - Logs generated while parsing the command line - options are buffered and printed later. - */ - buffered_logs.init(); - my_getopt_error_reporter= buffered_option_error_reporter; - my_charset_error_reporter= buffered_option_error_reporter; - pfs_param.m_pfs_instrument= const_cast(""); + mysql_mutex_lock(&LOCK_thread_count); + wsrep_running_threads++; + mysql_cond_signal(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); - int ho_error= handle_early_options(); + processor(thd); -#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE - if (ho_error == 0) + close_connection(thd, 0, 1); + + mysql_mutex_lock(&LOCK_thread_count); + wsrep_running_threads--; + mysql_cond_signal(&COND_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + + // Note: We can't call THD destructor without crashing + // if plugins have not been initialized. However, in most of the + // cases this means that pre SE initialization SST failed and + // we are going to exit anyway. + if (plugins_are_initialized) { - if (pfs_param.m_enabled && !opt_help && !opt_bootstrap) - { - /* Add sizing hints from the server sizing parameters. */ - pfs_param.m_hints.m_table_definition_cache= tdc_size; - pfs_param.m_hints.m_table_open_cache= tc_size; - pfs_param.m_hints.m_max_connections= max_connections; - pfs_param.m_hints.m_open_files_limit= open_files_limit; - PSI_hook= initialize_performance_schema(&pfs_param); - if (PSI_hook == NULL) - { - pfs_param.m_enabled= false; - buffered_logs.buffer(WARNING_LEVEL, - "Performance schema disabled (reason: init failed)."); - } - } + net_end(&thd->net); + MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1)); } -#else - /* - Other provider of the instrumentation interface should - initialize PSI_hook here: - - HAVE_PSI_INTERFACE is for the instrumentation interface - - WITH_PERFSCHEMA_STORAGE_ENGINE is for one implementation - of the interface, - but there could be alternate implementations, which is why - these two defines are kept separate. - */ -#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ - -#ifdef HAVE_PSI_INTERFACE - /* - Obtain the current performance schema instrumentation interface, - if available. - */ - if (PSI_hook) + else { - PSI *psi_server= (PSI*) PSI_hook->get_interface(PSI_CURRENT_VERSION); - if (likely(psi_server != NULL)) - { - set_psi_server(psi_server); - - /* - Now that we have parsed the command line arguments, and have - initialized the performance schema itself, the next step is to - register all the server instruments. - */ - init_server_psi_keys(); - /* Instrument the main thread */ - PSI_thread *psi= PSI_THREAD_CALL(new_thread)(key_thread_main, NULL, 0); - PSI_THREAD_CALL(set_thread)(psi); - - /* - Now that some instrumentation is in place, - recreate objects which were initialised early, - so that they are instrumented as well. - */ - my_thread_global_reinit(); - } + // TODO: lightweight cleanup to get rid of: + // 'Error in my_thread_global_end(): 2 threads didn't exit' + // at server shutdown } -#endif /* HAVE_PSI_INTERFACE */ - - init_error_log_mutex(); - - /* Initialize audit interface globals. Audit plugins are inited later. */ - mysql_audit_initialize(); - /* - Perform basic logger initialization logger. Should be called after - MY_INIT, as it initializes mutexes. Log tables are inited later. - */ - logger.init_base(); + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_lock(&LOCK_thread_count); + delete thd; + thread_count--; + mysql_mutex_unlock(&LOCK_thread_count); + } + return(NULL); +} -#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE - if (ho_error) +void wsrep_create_rollbacker() +{ + if (wsrep_provider && strcasecmp(wsrep_provider, "none")) { - /* - Parsing command line option failed, - Since we don't have a workable remaining_argc/remaining_argv - to continue the server initialization, this is as far as this - code can go. - This is the best effort to log meaningful messages: - - messages will be printed to stderr, which is not redirected yet, - - messages will be printed in the NT event log, for windows. - */ - buffered_logs.print(); - buffered_logs.cleanup(); - /* - Not enough initializations for unireg_abort() - Using exit() for windows. - */ - exit (ho_error); + pthread_t hThread; + /* create rollbacker */ + if (pthread_create( &hThread, &connection_attrib, + start_wsrep_THD, (void*)wsrep_rollback_process)) + WSREP_WARN("Can't create thread to manage wsrep rollback"); } -#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ +} -#ifdef _CUSTOMSTARTUPCONFIG_ - if (_cust_check_startup()) +void wsrep_create_appliers(long threads) +{ + if (!wsrep_connected) { - / * _cust_check_startup will report startup failure error * / - exit(1); + /* see wsrep_replication_start() for the logic */ + if (wsrep_cluster_address && strlen(wsrep_cluster_address) && + wsrep_provider && strcasecmp(wsrep_provider, "none")) + { + WSREP_ERROR("Trying to launch slave threads before creating " + "connection at '%s'", wsrep_cluster_address); + assert(0); + } + return; } -#endif - if (init_common_variables()) - unireg_abort(1); // Will do exit + long wsrep_threads=0; + pthread_t hThread; + while (wsrep_threads++ < threads) { + if (pthread_create( + &hThread, &connection_attrib, + start_wsrep_THD, (void*)wsrep_replication_process)) + WSREP_WARN("Can't create thread to manage wsrep replication"); + } +} +/**/ +static bool abort_replicated(THD *thd) +{ + bool ret_code= false; + if (thd->wsrep_query_state== QUERY_COMMITTING) + { + if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id); - init_signals(); + (void)wsrep_abort_thd(thd, thd, TRUE); + ret_code= true; + } + return ret_code; +} +/**/ +static inline bool is_client_connection(THD *thd) +{ +#if REMOVE +// REMOVE THIS LATER (lp:777201). Below we had to add an explicit check for +// wsrep_applier since wsrep_exec_mode didn't seem to always work +if (thd->wsrep_applier && thd->wsrep_exec_mode != REPL_RECV) +WSREP_WARN("applier has wsrep_exec_mode = %d", thd->wsrep_exec_mode); + + if ( thd->slave_thread || /* declared as mysql slave */ + thd->system_thread || /* declared as system thread */ + !thd->vio_ok() || /* server internal thread */ + thd->wsrep_exec_mode==REPL_RECV || /* applier or replaying thread */ + thd->wsrep_applier || /* wsrep slave applier */ + !thd->variables.wsrep_on) /* client, but fenced outside wsrep */ + return false; + + return true; +#else + return (thd->wsrep_client_thread && thd->variables.wsrep_on); +#endif /* REMOVE */ +} - my_thread_stack_size= my_setstacksize(&connection_attrib, - my_thread_stack_size); +static inline bool is_replaying_connection(THD *thd) +{ + bool ret; - (void) thr_setconcurrency(concurrency); // 10 by default + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); - select_thread=pthread_self(); - select_thread_in_use=1; + return ret; +} -#ifdef HAVE_LIBWRAP - libwrapName= my_progname+dirname_length(my_progname); - openlog(libwrapName, LOG_PID, LOG_AUTH); -#endif +static inline bool is_committing_connection(THD *thd) +{ + bool ret; -#ifndef DBUG_OFF - test_lc_time_sz(); - srand((uint) time(NULL)); -#endif + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false; + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); - /* - We have enough space for fiddling with the argv, continue - */ - check_data_home(mysql_real_data_home); - if (my_setwd(mysql_real_data_home, opt_abort ? 0 : MYF(MY_WME)) && !opt_abort) - unireg_abort(1); /* purecov: inspected */ + return ret; +} - if ((user_info= check_user(mysqld_user))) - { -#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) - if (locked_in_memory) // getuid() == 0 here - set_effective_user(user_info); - else -#endif - set_user(mysqld_user, user_info); - } +static bool have_client_connections() +{ + THD *tmp; - if (opt_bin_log && !global_system_variables.server_id) + I_List_iterator it(threads); + while ((tmp=it++)) { - global_system_variables.server_id= ::server_id= 1; -#ifdef EXTRA_DEBUG - sql_print_warning("You have enabled the binary log, but you haven't set " - "server-id to a non-zero value: we force server id to 1; " - "updates will be logged to the binary log, but " - "connections from slaves will not be accepted."); -#endif + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + if (is_client_connection(tmp) && tmp->killed == KILL_CONNECTION) + { + (void)abort_replicated(tmp); + return true; + } } + return false; +} - /* - The subsequent calls may take a long time : e.g. innodb log read. - Thus set the long running service control manager timeout - */ -#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) - Service.SetSlowStarting(slow_start_timeout); -#endif - - if (init_server_components()) - unireg_abort(1); - - init_ssl(); - network_init(); +/* + returns the number of wsrep appliers running. + However, the caller (thd parameter) is not taken in account + */ +static int have_wsrep_appliers(THD *thd) +{ + int ret= 0; + THD *tmp; -#ifdef __WIN__ - if (!opt_console) + I_List_iterator it(threads); + while ((tmp=it++)) { - if (reopen_fstreams(log_error_file, stdout, stderr)) - unireg_abort(1); - setbuf(stderr, NULL); - FreeConsole(); // Remove window + ret+= (tmp != thd && tmp->wsrep_applier); } -#endif - - /* - Initialize my_str_malloc() and my_str_free() - */ - my_str_malloc= &my_str_malloc_mysqld; - my_str_free= &my_str_free_mysqld; + return ret; +} - /* - init signals & alarm - After this we can't quit by a simple unireg_abort - */ - start_signal_handler(); // Creates pidfile - - if (mysql_rm_tmp_tables() || acl_init(opt_noacl) || - my_tz_init((THD *)0, default_tz_name, opt_bootstrap)) +static void wsrep_close_thread(THD *thd) +{ + thd->killed= KILL_CONNECTION; + MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd)); + if (thd->mysys_var) { - abort_loop=1; - select_thread_in_use=0; + thd->mysys_var->abort=1; + mysql_mutex_lock(&thd->mysys_var->mutex); + if (thd->mysys_var->current_cond) + { + mysql_mutex_lock(thd->mysys_var->current_mutex); + mysql_cond_broadcast(thd->mysys_var->current_cond); + mysql_mutex_unlock(thd->mysys_var->current_mutex); + } + mysql_mutex_unlock(&thd->mysys_var->mutex); + } +} - (void) pthread_kill(signal_thread, MYSQL_KILL_SIGNAL); +static my_bool have_committing_connections() +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - delete_pid_file(MYF(MY_WME)); + I_List_iterator it(threads); + while ((tmp=it++)) + { + if (!is_client_connection(tmp)) + continue; - if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET) - unlink(mysqld_unix_port); - exit(1); + if (is_committing_connection(tmp)) + { + mysql_mutex_unlock(&LOCK_thread_count); + return TRUE; + } } + mysql_mutex_unlock(&LOCK_thread_count); + return FALSE; +} - if (!opt_noacl) - (void) grant_init(); +int wsrep_wait_committing_connections_close(int wait_time) +{ + int sleep_time= 100; - if (!opt_noacl) + while (have_committing_connections() && wait_time > 0) { -#ifdef HAVE_DLOPEN - udf_init(); -#endif + WSREP_DEBUG("wait for committing transaction to close: %d", wait_time); + my_sleep(sleep_time); + wait_time -= sleep_time; } + if (have_committing_connections()) + { + return 1; + } + return 0; +} - init_status_vars(); - if (opt_bootstrap) /* If running with bootstrap, do not start replication. */ - opt_skip_slave_start= 1; - - binlog_unsafe_map_init(); - -#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE - initialize_performance_schema_acl(opt_bootstrap); +void wsrep_close_client_connections(my_bool wait_to_end) +{ /* - Do not check the structure of the performance schema tables - during bootstrap: - - the tables are not supposed to exist yet, bootstrap will create them - - a check would print spurious error messages + First signal all threads that it's time to die */ - if (! opt_bootstrap) - check_performance_schema(); -#endif - - initialize_information_schema_acl(); - execute_ddl_log_recovery(); + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - if (Events::init(opt_noacl || opt_bootstrap)) - unireg_abort(1); + bool kill_cached_threads_saved= kill_cached_threads; + kill_cached_threads= true; // prevent future threads caching + mysql_cond_broadcast(&COND_thread_cache); // tell cached threads to die -#ifdef WITH_WSREP /* WSREP AFTER SE */ - if (opt_bootstrap) - { - /*! bootstrap wsrep init was taken care of above */ - } - else + I_List_iterator it(threads); + while ((tmp=it++)) { - wsrep_SE_initialized(); - - if (wsrep_before_SE()) - { - /*! in case of no SST wsrep waits in view handler callback */ - wsrep_SE_init_grab(); - wsrep_SE_init_done(); - /*! in case of SST wsrep waits for wsrep->sst_received */ - wsrep_sst_continue(); - } - else - { - wsrep_init_startup (false); - } + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (!is_client_connection(tmp)) + continue; - wsrep_create_appliers(wsrep_slave_threads - 1); - } -#endif /* WITH_WSREP */ - if (opt_bootstrap) - { - select_thread_in_use= 0; // Allow 'kill' to work - bootstrap(mysql_stdin); - if (!kill_in_progress) - unireg_abort(bootstrap_error ? 1 : 0); - else + if (is_replaying_connection(tmp)) { - sleep(2); // Wait for kill - exit(0); + tmp->killed= KILL_CONNECTION; + continue; } - } - /* It's now safe to use thread specific memory */ - mysqld_server_initialized= 1; + /* replicated transactions must be skipped */ + if (abort_replicated(tmp)) + continue; - create_shutdown_thread(); - start_handle_manager(); + WSREP_DEBUG("closing connection %ld", tmp->thread_id); + wsrep_close_thread(tmp); + } + mysql_mutex_unlock(&LOCK_thread_count); - /* Copy default global rpl_filter to global_rpl_filter */ - copy_filter_setting(global_rpl_filter, get_or_create_rpl_filter("", 0)); + if (thread_count) + sleep(2); // Give threads time to die + mysql_mutex_lock(&LOCK_thread_count); /* - init_slave() must be called after the thread keys are created. - Some parts of the code (e.g. SHOW STATUS LIKE 'slave_running' and other - places) assume that active_mi != 0, so let's fail if it's 0 (out of - memory); a message has already been printed. + Force remaining threads to die by closing the connection to the client */ - if (init_slave() && !active_mi) + + I_List_iterator it2(threads); + while ((tmp=it2++)) { - unireg_abort(1); +#ifndef __bsdi__ // Bug in BSDI kernel + if (is_client_connection(tmp) && + !abort_replicated(tmp) && + !is_replaying_connection(tmp)) + { + WSREP_INFO("killing local connection: %ld",tmp->thread_id); + close_connection(tmp,0,0); + } +#endif } - if (opt_init_file && *opt_init_file) + DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); + if (wsrep_debug) + WSREP_INFO("waiting for client connections to close: %u", thread_count); + + while (wait_to_end && have_client_connections()) { - if (read_init_file(opt_init_file)) - unireg_abort(1); + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)", thread_count)); } - sql_print_information(ER_DEFAULT(ER_STARTUP),my_progname,server_version, - ((mysql_socket_getfd(unix_sock) == INVALID_SOCKET) ? - (char*) "" : mysqld_unix_port), - mysqld_port, - MYSQL_COMPILATION_COMMENT); -#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) - Service.SetRunning(); -#endif - - /* Signal threads waiting for server to be started */ - mysql_mutex_lock(&LOCK_server_started); - mysqld_server_started= 1; - mysql_cond_signal(&COND_server_started); - mysql_mutex_unlock(&LOCK_server_started); + kill_cached_threads= kill_cached_threads_saved; -#if defined(_WIN32) || defined(HAVE_SMEM) - handle_connections_methods(); -#else - handle_connections_sockets(); -#endif /* _WIN32 || HAVE_SMEM */ + mysql_mutex_unlock(&LOCK_thread_count); - /* (void) pthread_attr_destroy(&connection_attrib); */ + /* All client connection threads have now been aborted */ +} - DBUG_PRINT("quit",("Exiting main thread")); +void wsrep_close_applier(THD *thd) +{ + WSREP_DEBUG("closing applier %ld", thd->thread_id); + wsrep_close_thread(thd); +} -#ifndef __WIN__ -#ifdef EXTRA_DEBUG2 - sql_print_error("Before Lock_thread_count"); -#endif -#ifdef WITH_WSREP - WSREP_DEBUG("Before Lock_thread_count"); -#endif - mysql_mutex_lock(&LOCK_thread_count); - DBUG_PRINT("quit", ("Got thread_count mutex")); - select_thread_in_use=0; // For close_connections - mysql_mutex_unlock(&LOCK_thread_count); - mysql_cond_broadcast(&COND_thread_count); -#ifdef EXTRA_DEBUG2 - sql_print_error("After lock_thread_count"); -#endif -#endif /* __WIN__ */ +static void wsrep_close_threads(THD *thd) +{ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list -#ifdef HAVE_PSI_THREAD_INTERFACE - /* - Disable the main thread instrumentation, - to avoid recording events during the shutdown. - */ - PSI_THREAD_CALL(delete_current_thread)(); -#endif + I_List_iterator it(threads); + while ((tmp=it++)) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (tmp->wsrep_applier && tmp != thd) + { + WSREP_DEBUG("closing wsrep thread %ld", tmp->thread_id); + wsrep_close_thread (tmp); + } + } - /* Wait until cleanup is done */ - mysql_mutex_lock(&LOCK_thread_count); - while (!ready_to_exit) - mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); mysql_mutex_unlock(&LOCK_thread_count); +} -#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) - if (Service.IsNT() && start_mode) - Service.Stop(); - else - { - Service.SetShutdownEvent(0); - if (hEventShutdown) - CloseHandle(hEventShutdown); - } -#endif - mysqld_exit(0); - return 0; -} - -#endif /* !EMBEDDED_LIBRARY */ - - -/**************************************************************************** - Main and thread entry function for Win32 - (all this is needed only to run mysqld as a service on WinNT) -****************************************************************************/ - -#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) -int mysql_service(void *p) +void wsrep_close_applier_threads(int count) { - if (my_thread_init()) - return 1; - - if (use_opt_args) - win_main(opt_argc, opt_argv); - else - win_main(Service.my_argc, Service.my_argv); - - my_thread_end(); - return 0; -} - - -/* Quote string if it contains space, else copy */ + THD *tmp; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list -static char *add_quoted_string(char *to, const char *from, char *to_end) -{ - uint length= (uint) (to_end-to); + I_List_iterator it(threads); + while ((tmp=it++) && count) + { + DBUG_PRINT("quit",("Informing thread %ld that it's time to die", + tmp->thread_id)); + /* We skip slave threads & scheduler on this first loop through. */ + if (tmp->wsrep_applier) + { + WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id); + tmp->wsrep_applier_closing= TRUE; + count--; + } + } - if (!strchr(from, ' ')) - return strmake(to, from, length-1); - return strxnmov(to, length-1, "\"", from, "\"", NullS); + mysql_mutex_unlock(&LOCK_thread_count); } - -/** - Handle basic handling of services, like installation and removal. - - @param argv Pointer to argument list - @param servicename Internal name of service - @param displayname Display name of service (in taskbar ?) - @param file_path Path to this program - @param startup_option Startup option to mysqld - - @retval 0 option handled - @retval 1 Could not handle option -*/ - -static bool -default_service_handling(char **argv, - const char *servicename, - const char *displayname, - const char *file_path, - const char *extra_opt, - const char *account_name) +void wsrep_wait_appliers_close(THD *thd) { - char path_and_service[FN_REFLEN+FN_REFLEN+32], *pos, *end; - const char *opt_delim; - end= path_and_service + sizeof(path_and_service)-3; - - /* We have to quote filename if it contains spaces */ - pos= add_quoted_string(path_and_service, file_path, end); - if (*extra_opt) + /* Wait for wsrep appliers to gracefully exit */ + mysql_mutex_lock(&LOCK_thread_count); + while (have_wsrep_appliers(thd) > 1) + // 1 is for rollbacker thread which needs to be killed explicitly. + // This gotta be fixed in a more elegant manner if we gonna have arbitrary + // number of non-applier wsrep threads. { - /* - Add option after file_path. There will be zero or one extra option. It's - assumed to be --defaults-file=file but isn't checked. The variable (not - the option name) should be quoted if it contains a string. - */ - *pos++= ' '; - if (opt_delim= strchr(extra_opt, '=')) + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) { - size_t length= ++opt_delim - extra_opt; - pos= strnmov(pos, extra_opt, length); + mysql_mutex_unlock(&LOCK_thread_count); + my_sleep(100); + mysql_mutex_lock(&LOCK_thread_count); } else - opt_delim= extra_opt; - - pos= add_quoted_string(pos, opt_delim, end); + mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); + DBUG_PRINT("quit",("One applier died (count=%u)",thread_count)); } - /* We must have servicename last */ - *pos++= ' '; - (void) add_quoted_string(pos, servicename, end); - - if (Service.got_service_option(argv, "install")) + mysql_mutex_unlock(&LOCK_thread_count); + /* Now kill remaining wsrep threads: rollbacker */ + wsrep_close_threads (thd); + /* and wait for them to die */ + mysql_mutex_lock(&LOCK_thread_count); + while (have_wsrep_appliers(thd) > 0) { - Service.Install(1, servicename, displayname, path_and_service, - account_name); - return 0; + if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + { + mysql_mutex_unlock(&LOCK_thread_count); + my_sleep(100); + mysql_mutex_lock(&LOCK_thread_count); + } + else + mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)",thread_count)); } - if (Service.got_service_option(argv, "install-manual")) + mysql_mutex_unlock(&LOCK_thread_count); + + /* All wsrep applier threads have now been aborted. However, if this thread + is also applier, we are still running... + */ +} + +void wsrep_kill_mysql(THD *thd) +{ + if (mysqld_server_started) { - Service.Install(0, servicename, displayname, path_and_service, - account_name); - return 0; + if (!shutdown_in_progress) + { + WSREP_INFO("starting shutdown"); + kill_mysql(); + } } - if (Service.got_service_option(argv, "remove")) + else { - Service.Remove(servicename); - return 0; + unireg_abort(1); } - return 1; } +#endif /* WITH_WSREP */ - -int mysqld_main(int argc, char **argv) +#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) +static void handle_connections_methods() { - my_progname= argv[0]; - - /* - When several instances are running on the same machine, we - need to have an unique named hEventShudown through the - application PID e.g.: MySQLShutdown1890; MySQLShutdown2342 - */ - int10_to_str((int) GetCurrentProcessId(),strmov(shutdown_event_name, - "MySQLShutdown"), 10); - - /* Must be initialized early for comparison of service name */ - system_charset_info= &my_charset_utf8_general_ci; - - if (my_init()) + pthread_t hThread; + DBUG_ENTER("handle_connections_methods"); + if (hPipe == INVALID_HANDLE_VALUE && + (!have_tcpip || opt_disable_networking) && + !opt_enable_shared_memory) { - fprintf(stderr, "my_init() failed."); - return 1; + sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS"); + unireg_abort(1); // Will not return } - if (Service.GetOS()) /* true NT family */ + mysql_mutex_lock(&LOCK_thread_count); + mysql_cond_init(key_COND_handler_count, &COND_handler_count, NULL); + handler_count=0; + if (hPipe != INVALID_HANDLE_VALUE) { - char file_path[FN_REFLEN]; - my_path(file_path, argv[0], ""); /* Find name in path */ - fn_format(file_path,argv[0],file_path,"", - MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS); - - if (argc == 2) + handler_count++; + if (mysql_thread_create(key_thread_handle_con_namedpipes, + &hThread, &connection_attrib, + handle_connections_namedpipes, 0)) { - if (!default_service_handling(argv, MYSQL_SERVICENAME, MYSQL_SERVICENAME, - file_path, "", NULL)) - return 0; - if (Service.IsService(argv[1])) /* Start an optional service */ - { - /* - Only add the service name to the groups read from the config file - if it's not "MySQL". (The default service name should be 'mysqld' - but we started a bad tradition by calling it MySQL from the start - and we are now stuck with it. - */ - if (my_strcasecmp(system_charset_info, argv[1],"mysql")) - load_default_groups[load_default_groups_sz-2]= argv[1]; - start_mode= 1; - Service.Init(argv[1], mysql_service); - return 0; - } + sql_print_warning("Can't create thread to handle named pipes"); + handler_count--; } - else if (argc == 3) /* install or remove any optional service */ + } + if (have_tcpip && !opt_disable_networking) + { + handler_count++; + if (mysql_thread_create(key_thread_handle_con_sockets, + &hThread, &connection_attrib, + handle_connections_sockets_thread, 0)) { - if (!default_service_handling(argv, argv[2], argv[2], file_path, "", - NULL)) - return 0; - if (Service.IsService(argv[2])) - { - /* - mysqld was started as - mysqld --defaults-file=my_path\my.ini service-name - */ - use_opt_args=1; - opt_argc= 2; // Skip service-name - opt_argv=argv; - start_mode= 1; - if (my_strcasecmp(system_charset_info, argv[2],"mysql")) - load_default_groups[load_default_groups_sz-2]= argv[2]; - Service.Init(argv[2], mysql_service); - return 0; - } + sql_print_warning("Can't create thread to handle TCP/IP"); + handler_count--; } - else if (argc == 4 || argc == 5) - { - /* - This may seem strange, because we handle --local-service while - preserving 4.1's behavior of allowing any one other argument that is - passed to the service on startup. (The assumption is that this is - --defaults-file=file, but that was not enforced in 4.1, so we don't - enforce it here.) - */ - const char *extra_opt= NullS; - const char *account_name = NullS; - int index; - for (index = 3; index < argc; index++) - { - if (!strcmp(argv[index], "--local-service")) - account_name= "NT AUTHORITY\\LocalService"; - else - extra_opt= argv[index]; - } - - if (argc == 4 || account_name) - if (!default_service_handling(argv, argv[2], argv[2], file_path, - extra_opt, account_name)) - return 0; - } - else if (argc == 1 && Service.IsService(MYSQL_SERVICENAME)) + } +#ifdef HAVE_SMEM + if (opt_enable_shared_memory) + { + handler_count++; + if (mysql_thread_create(key_thread_handle_con_sharedmem, + &hThread, &connection_attrib, + handle_connections_shared_memory, 0)) { - /* start the default service */ - start_mode= 1; - Service.Init(MYSQL_SERVICENAME, mysql_service); - return 0; + sql_print_warning("Can't create thread to handle shared memory"); + handler_count--; } } - /* Start as standalone server */ - Service.my_argc=argc; - Service.my_argv=argv; - mysql_service(NULL); - return 0; -} -#endif - - -/** - Execute all commands from a file. Used by the mysql_install_db script to - create MySQL privilege tables without having to start a full MySQL server. -*/ - -static void bootstrap(MYSQL_FILE *file) -{ - DBUG_ENTER("bootstrap"); - - THD *thd= new THD; -#ifdef WITH_WSREP - thd->variables.wsrep_on= 0; #endif - thd->bootstrap=1; - my_net_init(&thd->net,(st_vio*) 0, MYF(0)); - thd->max_client_packet_length= thd->net.max_packet; - thd->security_ctx->master_access= ~(ulong)0; - thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; - thread_count++; // Safe as only one thread running - in_bootstrap= TRUE; - bootstrap_file=file; -#ifndef EMBEDDED_LIBRARY // TODO: Enable this - if (mysql_thread_create(key_thread_bootstrap, - &thd->real_id, &connection_attrib, handle_bootstrap, - (void*) thd)) - { - sql_print_warning("Can't create thread to handle bootstrap"); - bootstrap_error=-1; - DBUG_VOID_RETURN; - } - /* Wait for thread to die */ - mysql_mutex_lock(&LOCK_thread_count); - while (in_bootstrap) - { - mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); - DBUG_PRINT("quit",("One thread died (count=%u)",thread_count)); - } + while (handler_count > 0) + mysql_cond_wait(&COND_handler_count, &LOCK_thread_count); mysql_mutex_unlock(&LOCK_thread_count); -#else - thd->mysql= 0; - do_handle_bootstrap(thd); -#endif - DBUG_VOID_RETURN; } - -static bool read_init_file(char *file_name) +void decrement_handler_count() { - MYSQL_FILE *file; - DBUG_ENTER("read_init_file"); - DBUG_PRINT("enter",("name: %s",file_name)); - if (!(file= mysql_file_fopen(key_file_init, file_name, - O_RDONLY, MYF(MY_WME)))) - DBUG_RETURN(TRUE); - bootstrap(file); - mysql_file_fclose(file, MYF(MY_WME)); - DBUG_RETURN(FALSE); + mysql_mutex_lock(&LOCK_thread_count); + handler_count--; + mysql_cond_signal(&COND_handler_count); + mysql_mutex_unlock(&LOCK_thread_count); + my_thread_end(); } +#else +#define decrement_handler_count() +#endif /* defined(_WIN32) || defined(HAVE_SMEM) */ -/** - Increment number of created threads +#ifndef EMBEDDED_LIBRARY +#ifndef DBUG_OFF +/* + Debugging helper function to keep the locale database + (see sql_locale.cc) and max_month_name_length and + max_day_name_length variable values in consistent state. */ -void inc_thread_created(void) +static void test_lc_time_sz() { - thread_created++; + DBUG_ENTER("test_lc_time_sz"); + for (MY_LOCALE **loc= my_locales; *loc; loc++) + { + uint max_month_len= 0; + uint max_day_len = 0; + for (const char **month= (*loc)->month_names->type_names; *month; month++) + { + set_if_bigger(max_month_len, + my_numchars_mb(&my_charset_utf8_general_ci, + *month, *month + strlen(*month))); + } + for (const char **day= (*loc)->day_names->type_names; *day; day++) + { + set_if_bigger(max_day_len, + my_numchars_mb(&my_charset_utf8_general_ci, + *day, *day + strlen(*day))); + } + if ((*loc)->max_month_name_length != max_month_len || + (*loc)->max_day_name_length != max_day_len) + { + DBUG_PRINT("Wrong max day name(or month name) length for locale:", + ("%s", (*loc)->name)); + DBUG_ASSERT(0); + } + } + DBUG_VOID_RETURN; } +#endif//DBUG_OFF -#ifndef EMBEDDED_LIBRARY -/* - Simple scheduler that use the main thread to handle the request +#ifdef __WIN__ +int win_main(int argc, char **argv) +#else +int mysqld_main(int argc, char **argv) +#endif +{ + /* + Perform basic thread library and malloc initialization, + to be able to read defaults files and parse options. + */ + my_progname= argv[0]; + sf_leaking_memory= 1; // no safemalloc memory leak reports if we exit early + mysqld_server_started= mysqld_server_initialized= 0; - NOTES - This is only used for debugging, when starting mysqld with - --thread-handling=no-threads or --one-thread +#ifdef HAVE_NPTL + ld_assume_kernel_is_set= (getenv("LD_ASSUME_KERNEL") != 0); +#endif +#ifndef _WIN32 + // For windows, my_init() is called from the win specific mysqld_main + if (my_init()) // init my_sys library & pthreads + { + fprintf(stderr, "my_init() failed."); + return 1; + } +#endif - When we enter this function, LOCK_thread_count is hold! -*/ + orig_argc= argc; + orig_argv= argv; + my_getopt_use_args_separator= TRUE; + if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv)) + return 1; + my_getopt_use_args_separator= FALSE; + defaults_argc= argc; + defaults_argv= argv; + remaining_argc= argc; + remaining_argv= argv; -void handle_connection_in_main_thread(THD *thd) -{ - mysql_mutex_assert_owner(&LOCK_thread_count); - thread_cache_size=0; // Safety - threads.append(thd); - mysql_mutex_unlock(&LOCK_thread_count); - thd->start_utime= microsecond_interval_timer(); - do_handle_one_connection(thd); -} + /* Must be initialized early for comparison of options name */ + system_charset_info= &my_charset_utf8_general_ci; + sys_var_init(); -/* - Scheduler that uses one thread per connection -*/ +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + /* + Initialize the array of performance schema instrument configurations. + */ + init_pfs_instrument_array(); +#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ + /* + Logs generated while parsing the command line + options are buffered and printed later. + */ + buffered_logs.init(); + my_getopt_error_reporter= buffered_option_error_reporter; + my_charset_error_reporter= buffered_option_error_reporter; + pfs_param.m_pfs_instrument= const_cast(""); -void create_thread_to_handle_connection(THD *thd) -{ - DBUG_ENTER("create_thread_to_handle_connection"); - mysql_mutex_assert_owner(&LOCK_thread_count); + int ho_error= handle_early_options(); - /* Check if we can get thread from the cache */ - if (cached_thread_count > wake_thread) +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + if (ho_error == 0) { - mysql_mutex_lock(&LOCK_thread_cache); - /* Recheck condition when we have the lock */ - if (cached_thread_count > wake_thread) + if (pfs_param.m_enabled && !opt_help && !opt_bootstrap) { - mysql_mutex_unlock(&LOCK_thread_count); - /* Get thread from cache */ - thread_cache.push_back(thd); - wake_thread++; - mysql_cond_signal(&COND_thread_cache); - mysql_mutex_unlock(&LOCK_thread_cache); - DBUG_PRINT("info",("Thread created")); - DBUG_VOID_RETURN; + /* Add sizing hints from the server sizing parameters. */ + pfs_param.m_hints.m_table_definition_cache= tdc_size; + pfs_param.m_hints.m_table_open_cache= tc_size; + pfs_param.m_hints.m_max_connections= max_connections; + pfs_param.m_hints.m_open_files_limit= open_files_limit; + PSI_hook= initialize_performance_schema(&pfs_param); + if (PSI_hook == NULL) + { + pfs_param.m_enabled= false; + buffered_logs.buffer(WARNING_LEVEL, + "Performance schema disabled (reason: init failed)."); + } } - mysql_mutex_unlock(&LOCK_thread_cache); } - - char error_message_buff[MYSQL_ERRMSG_SIZE]; - /* Create new thread to handle connection */ - int error; - thread_created++; - threads.append(thd); - DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); - thd->prior_thr_create_utime= microsecond_interval_timer(); - if ((error= mysql_thread_create(key_thread_one_connection, - &thd->real_id, &connection_attrib, - handle_one_connection, - (void*) thd))) - { - /* purecov: begin inspected */ - DBUG_PRINT("error", - ("Can't create thread to handle request (error %d)", - error)); - thd->killed= KILL_CONNECTION; // Safety - mysql_mutex_unlock(&LOCK_thread_count); - - mysql_mutex_lock(&LOCK_connection_count); - (*thd->scheduler->connection_count)--; - mysql_mutex_unlock(&LOCK_connection_count); - - statistic_increment(aborted_connects,&LOCK_status); - statistic_increment(connection_errors_internal, &LOCK_status); - /* Can't use my_error() since store_globals has not been called. */ - my_snprintf(error_message_buff, sizeof(error_message_buff), - ER_THD(thd, ER_CANT_CREATE_THREAD), error); - net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, NULL); -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES ,0); #else - close_connection(thd, ER_OUT_OF_RESOURCES); -#endif /* WITH_WSREP */ - - mysql_mutex_lock(&LOCK_thread_count); - thd->unlink(); - mysql_mutex_unlock(&LOCK_thread_count); - delete thd; - thread_safe_decrement32(&thread_count, &thread_count_lock); - return; - /* purecov: end */ - } - mysql_mutex_unlock(&LOCK_thread_count); - DBUG_PRINT("info",("Thread created")); - DBUG_VOID_RETURN; -} - + /* + Other provider of the instrumentation interface should + initialize PSI_hook here: + - HAVE_PSI_INTERFACE is for the instrumentation interface + - WITH_PERFSCHEMA_STORAGE_ENGINE is for one implementation + of the interface, + but there could be alternate implementations, which is why + these two defines are kept separate. + */ +#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ -/** - Create new thread to handle incoming connection. +#ifdef HAVE_PSI_INTERFACE + /* + Obtain the current performance schema instrumentation interface, + if available. + */ + if (PSI_hook) + { + PSI *psi_server= (PSI*) PSI_hook->get_interface(PSI_CURRENT_VERSION); + if (likely(psi_server != NULL)) + { + set_psi_server(psi_server); - This function will create new thread to handle the incoming - connection. If there are idle cached threads one will be used. - 'thd' will be pushed into 'threads'. + /* + Now that we have parsed the command line arguments, and have + initialized the performance schema itself, the next step is to + register all the server instruments. + */ + init_server_psi_keys(); + /* Instrument the main thread */ + PSI_thread *psi= PSI_THREAD_CALL(new_thread)(key_thread_main, NULL, 0); + PSI_THREAD_CALL(set_thread)(psi); - In single-threaded mode (\#define ONE_THREAD) connection will be - handled inside this function. + /* + Now that some instrumentation is in place, + recreate objects which were initialised early, + so that they are instrumented as well. + */ + my_thread_global_reinit(); + } + } +#endif /* HAVE_PSI_INTERFACE */ - @param[in,out] thd Thread handle of future thread. -*/ + init_error_log_mutex(); -static void create_new_thread(THD *thd) -{ - DBUG_ENTER("create_new_thread"); + /* Initialize audit interface globals. Audit plugins are inited later. */ + mysql_audit_initialize(); /* - Don't allow too many connections. We roughly check here that we allow - only (max_connections + 1) connections. + Perform basic logger initialization logger. Should be called after + MY_INIT, as it initializes mutexes. Log tables are inited later. */ + logger.init_base(); - mysql_mutex_lock(&LOCK_connection_count); - - if (*thd->scheduler->connection_count >= - *thd->scheduler->max_connections + 1|| abort_loop) +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + if (ho_error) { - mysql_mutex_unlock(&LOCK_connection_count); + /* + Parsing command line option failed, + Since we don't have a workable remaining_argc/remaining_argv + to continue the server initialization, this is as far as this + code can go. + This is the best effort to log meaningful messages: + - messages will be printed to stderr, which is not redirected yet, + - messages will be printed in the NT event log, for windows. + */ + buffered_logs.print(); + buffered_logs.cleanup(); + /* + Not enough initializations for unireg_abort() + Using exit() for windows. + */ + exit (ho_error); + } +#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ - DBUG_PRINT("error",("Too many connections")); -#ifdef WITH_WSREP - close_connection(thd, ER_CON_COUNT_ERROR, 1); -#else - close_connection(thd, ER_CON_COUNT_ERROR); -#endif /* WITH_WSREP */ - statistic_increment(denied_connections, &LOCK_status); - delete thd; - statistic_increment(connection_errors_max_connection, &LOCK_status); - DBUG_VOID_RETURN; +#ifdef _CUSTOMSTARTUPCONFIG_ + if (_cust_check_startup()) + { + / * _cust_check_startup will report startup failure error * / + exit(1); } +#endif - ++*thd->scheduler->connection_count; + if (init_common_variables()) + unireg_abort(1); // Will do exit - if (connection_count + extra_connection_count > max_used_connections) - max_used_connections= connection_count + extra_connection_count; + init_signals(); - mysql_mutex_unlock(&LOCK_connection_count); + my_thread_stack_size= my_setstacksize(&connection_attrib, + my_thread_stack_size); - thread_safe_increment32(&thread_count, &thread_count_lock); + (void) thr_setconcurrency(concurrency); // 10 by default + + select_thread=pthread_self(); + select_thread_in_use=1; + +#ifdef HAVE_LIBWRAP + libwrapName= my_progname+dirname_length(my_progname); + openlog(libwrapName, LOG_PID, LOG_AUTH); +#endif + +#ifndef DBUG_OFF + test_lc_time_sz(); + srand((uint) time(NULL)); +#endif - /* Start a new thread to handle connection. */ - mysql_mutex_lock(&LOCK_thread_count); /* - The initialization of thread_id is done in create_embedded_thd() for - the embedded library. - TODO: refactor this to avoid code duplication there + We have enough space for fiddling with the argv, continue */ - thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; + check_data_home(mysql_real_data_home); + if (my_setwd(mysql_real_data_home, opt_abort ? 0 : MYF(MY_WME)) && !opt_abort) + unireg_abort(1); /* purecov: inspected */ - MYSQL_CALLBACK(thd->scheduler, add_connection, (thd)); + if ((user_info= check_user(mysqld_user))) + { +#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) + if (locked_in_memory) // getuid() == 0 here + set_effective_user(user_info); + else +#endif + set_user(mysqld_user, user_info); + } - DBUG_VOID_RETURN; -} -#endif /* EMBEDDED_LIBRARY */ + if (opt_bin_log && !global_system_variables.server_id) + { + global_system_variables.server_id= ::server_id= 1; +#ifdef EXTRA_DEBUG + sql_print_warning("You have enabled the binary log, but you haven't set " + "server-id to a non-zero value: we force server id to 1; " + "updates will be logged to the binary log, but " + "connections from slaves will not be accepted."); +#endif + } + /* + The subsequent calls may take a long time : e.g. innodb log read. + Thus set the long running service control manager timeout + */ +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) + Service.SetSlowStarting(slow_start_timeout); +#endif -#ifdef SIGNALS_DONT_BREAK_READ -inline void kill_broken_server() -{ - /* hack to get around signals ignored in syscalls for problem OS's */ - if (mysql_socket_getfd(unix_sock) == INVALID_SOCKET || - (!opt_disable_networking && - mysql_socket_getfd(base_ip_sock) == INVALID_SOCKET)) + if (init_server_components()) + unireg_abort(1); + + init_ssl(); + network_init(); + +#ifdef __WIN__ + if (!opt_console) { - select_thread_in_use = 0; - /* The following call will never return */ - DBUG_PRINT("general", ("killing server because socket is closed")); - kill_server((void*) MYSQL_KILL_SIGNAL); + if (reopen_fstreams(log_error_file, stdout, stderr)) + unireg_abort(1); + setbuf(stderr, NULL); + FreeConsole(); // Remove window } -} -#define MAYBE_BROKEN_SYSCALL kill_broken_server(); -#else -#define MAYBE_BROKEN_SYSCALL #endif - /* Handle new connections and spawn new process to handle them */ + /* + Initialize my_str_malloc() and my_str_free() + */ + my_str_malloc= &my_str_malloc_mysqld; + my_str_free= &my_str_free_mysqld; -#ifndef EMBEDDED_LIBRARY +#ifdef WITH_WSREP /* WSREP AFTER SE */ + if (wsrep_recovery) + { + select_thread_in_use= 0; + wsrep_recover(); + unireg_abort(0); + } +#endif /* WITH_WSREP */ -void handle_connections_sockets() -{ - MYSQL_SOCKET sock= mysql_socket_invalid(); - MYSQL_SOCKET new_sock= mysql_socket_invalid(); - uint error_count=0; - THD *thd; - struct sockaddr_storage cAddr; - int ip_flags __attribute__((unused))=0; - int socket_flags __attribute__((unused))= 0; - int extra_ip_flags __attribute__((unused))=0; - int flags=0,retval; - st_vio *vio_tmp; - bool is_unix_sock; -#ifdef HAVE_POLL - int socket_count= 0; - struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock - MYSQL_SOCKET pfs_fds[3]; // for performance schema -#define setup_fds(X) \ - mysql_socket_set_thread_owner(X); \ - pfs_fds[socket_count]= (X); \ - fds[socket_count].fd= mysql_socket_getfd(X); \ - fds[socket_count].events= POLLIN; \ - socket_count++ -#else -#define setup_fds(X) FD_SET(mysql_socket_getfd(X),&clientFDs) - fd_set readFDs,clientFDs; - FD_ZERO(&clientFDs); -#endif - - DBUG_ENTER("handle_connections_sockets"); + /* + init signals & alarm + After this we can't quit by a simple unireg_abort + */ + start_signal_handler(); // Creates pidfile - if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET) + if (mysql_rm_tmp_tables() || acl_init(opt_noacl) || + my_tz_init((THD *)0, default_tz_name, opt_bootstrap)) { - setup_fds(base_ip_sock); - ip_flags = fcntl(mysql_socket_getfd(base_ip_sock), F_GETFL, 0); + abort_loop=1; + select_thread_in_use=0; + + (void) pthread_kill(signal_thread, MYSQL_KILL_SIGNAL); + + delete_pid_file(MYF(MY_WME)); + + if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET) + unlink(mysqld_unix_port); + exit(1); } - if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET) + + if (!opt_noacl) + (void) grant_init(); + + if (!opt_noacl) { - setup_fds(extra_ip_sock); - extra_ip_flags = fcntl(mysql_socket_getfd(extra_ip_sock), F_GETFL, 0); - } -#ifdef HAVE_SYS_UN_H - setup_fds(unix_sock); - socket_flags=fcntl(mysql_socket_getfd(unix_sock), F_GETFL, 0); +#ifdef HAVE_DLOPEN + udf_init(); #endif + } - DBUG_PRINT("general",("Waiting for connections.")); - MAYBE_BROKEN_SYSCALL; - while (!abort_loop) - { -#ifdef HAVE_POLL - retval= poll(fds, socket_count, -1); -#else - readFDs=clientFDs; - retval= select((int) 0,&readFDs,0,0,0); + init_status_vars(); + if (opt_bootstrap) /* If running with bootstrap, do not start replication. */ + opt_skip_slave_start= 1; + + binlog_unsafe_map_init(); + +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE + initialize_performance_schema_acl(opt_bootstrap); + /* + Do not check the structure of the performance schema tables + during bootstrap: + - the tables are not supposed to exist yet, bootstrap will create them + - a check would print spurious error messages + */ + if (! opt_bootstrap) + check_performance_schema(); #endif - if (retval < 0) - { - if (socket_errno != SOCKET_EINTR) - { - /* - select(2)/poll(2) failed on the listening port. - There is not much details to report about the client, - increment the server global status variable. - */ - statistic_increment(connection_errors_accept, &LOCK_status); - if (!select_errors++ && !abort_loop) /* purecov: inspected */ - sql_print_error("mysqld: Got error %d from select",socket_errno); /* purecov: inspected */ - } - MAYBE_BROKEN_SYSCALL - continue; - } + initialize_information_schema_acl(); - if (abort_loop) - { - MAYBE_BROKEN_SYSCALL; - break; - } + execute_ddl_log_recovery(); - /* Is this a new connection request ? */ -#ifdef HAVE_POLL - for (int i= 0; i < socket_count; ++i) - { - if (fds[i].revents & POLLIN) - { - sock= pfs_fds[i]; - flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0); - break; - } - } -#else // HAVE_POLL - if (FD_ISSET(mysql_socket_getfd(base_ip_sock),&readFDs)) + if (Events::init(opt_noacl || opt_bootstrap)) + unireg_abort(1); + +#ifdef WITH_WSREP /* WSREP AFTER SE */ + if (opt_bootstrap) + { + /*! bootstrap wsrep init was taken care of above */ + } + else + { + wsrep_SE_initialized(); + + if (wsrep_before_SE()) { - sock= base_ip_sock; - flags= ip_flags; + /*! in case of no SST wsrep waits in view handler callback */ + wsrep_SE_init_grab(); + wsrep_SE_init_done(); + /*! in case of SST wsrep waits for wsrep->sst_received */ + wsrep_sst_continue(); } else - if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs)) { - sock= extra_ip_sock; - flags= extra_ip_flags; + wsrep_init_startup (false); } + + wsrep_create_appliers(wsrep_slave_threads - 1); + } +#endif /* WITH_WSREP */ + if (opt_bootstrap) + { + select_thread_in_use= 0; // Allow 'kill' to work + bootstrap(mysql_stdin); + if (!kill_in_progress) + unireg_abort(bootstrap_error ? 1 : 0); else { - sock = unix_sock; - flags= socket_flags; + sleep(2); // Wait for kill + exit(0); } -#endif // HAVE_POLL + } -#if !defined(NO_FCNTL_NONBLOCK) - if (!(test_flags & TEST_BLOCKING)) - { -#if defined(O_NONBLOCK) - fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK); -#elif defined(O_NDELAY) - fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY); -#endif - } -#endif /* NO_FCNTL_NONBLOCK */ - for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++) - { - size_socket length= sizeof(struct sockaddr_storage); - new_sock= mysql_socket_accept(key_socket_client_connection, sock, - (struct sockaddr *)(&cAddr), - &length); - if (mysql_socket_getfd(new_sock) != INVALID_SOCKET || - (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)) - break; - MAYBE_BROKEN_SYSCALL; -#if !defined(NO_FCNTL_NONBLOCK) - if (!(test_flags & TEST_BLOCKING)) - { - if (retry == MAX_ACCEPT_RETRY - 1) - { - // Try without O_NONBLOCK - fcntl(mysql_socket_getfd(sock), F_SETFL, flags); - } - } -#endif - } -#if !defined(NO_FCNTL_NONBLOCK) - if (!(test_flags & TEST_BLOCKING)) - fcntl(mysql_socket_getfd(sock), F_SETFL, flags); -#endif - if (mysql_socket_getfd(new_sock) == INVALID_SOCKET) - { - /* - accept(2) failed on the listening port, after many retries. - There is not much details to report about the client, - increment the server global status variable. - */ - statistic_increment(connection_errors_accept, &LOCK_status); - if ((error_count++ & 255) == 0) // This can happen often - sql_perror("Error in accept"); - MAYBE_BROKEN_SYSCALL; - if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE) - sleep(1); // Give other threads some time - continue; - } -#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) - (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC); -#endif /* WITH_WSREP */ + /* It's now safe to use thread specific memory */ + mysqld_server_initialized= 1; -#ifdef HAVE_LIBWRAP - { - if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) || - mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) - { - struct request_info req; - signal(SIGCHLD, SIG_DFL); - request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, - mysql_socket_getfd(new_sock), NULL); - my_fromhost(&req); - if (!my_hosts_access(&req)) - { - /* - This may be stupid but refuse() includes an exit(0) - which we surely don't want... - clean_exit() - same stupid thing ... - */ - syslog(deny_severity, "refused connect from %s", - my_eval_client(&req)); + create_shutdown_thread(); + start_handle_manager(); - /* - C++ sucks (the gibberish in front just translates the supplied - sink function pointer in the req structure from a void (*sink)(); - to a void(*sink)(int) if you omit the cast, the C++ compiler - will cry... - */ - if (req.sink) - ((void (*)(int))req.sink)(req.fd); + /* Copy default global rpl_filter to global_rpl_filter */ + copy_filter_setting(global_rpl_filter, get_or_create_rpl_filter("", 0)); - (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) mysql_socket_close(new_sock); - /* - The connection was refused by TCP wrappers. - There are no details (by client IP) available to update the host_cache. - */ - statistic_increment(connection_tcpwrap_errors, &LOCK_status); - continue; - } - } - } -#endif /* HAVE_LIBWRAP */ + /* + init_slave() must be called after the thread keys are created. + Some parts of the code (e.g. SHOW STATUS LIKE 'slave_running' and other + places) assume that active_mi != 0, so let's fail if it's 0 (out of + memory); a message has already been printed. + */ + if (init_slave() && !active_mi) + { + unireg_abort(1); + } - /* - ** Don't allow too many connections - */ + if (opt_init_file && *opt_init_file) + { + if (read_init_file(opt_init_file)) + unireg_abort(1); + } - DBUG_PRINT("info", ("Creating THD for new connection")); - if (!(thd= new THD)) - { - (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) mysql_socket_close(new_sock); - statistic_increment(connection_errors_internal, &LOCK_status); - continue; - } - /* Set to get io buffers to be part of THD */ - set_current_thd(thd); + sql_print_information(ER_DEFAULT(ER_STARTUP),my_progname,server_version, + ((mysql_socket_getfd(unix_sock) == INVALID_SOCKET) ? + (char*) "" : mysqld_unix_port), + mysqld_port, + MYSQL_COMPILATION_COMMENT); +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) + Service.SetRunning(); +#endif - is_unix_sock= (mysql_socket_getfd(sock) == - mysql_socket_getfd(unix_sock)); + /* Signal threads waiting for server to be started */ + mysql_mutex_lock(&LOCK_server_started); + mysqld_server_started= 1; + mysql_cond_signal(&COND_server_started); + mysql_mutex_unlock(&LOCK_server_started); - if (!(vio_tmp= - mysql_socket_vio_new(new_sock, - is_unix_sock ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, - is_unix_sock ? VIO_LOCALHOST: 0)) || - my_net_init(&thd->net, vio_tmp, MYF(MY_THREAD_SPECIFIC))) - { - /* - Only delete the temporary vio if we didn't already attach it to the - NET object. The destructor in THD will delete any initialized net - structure. - */ - if (vio_tmp && thd->net.vio != vio_tmp) - vio_delete(vio_tmp); - else - { - (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) mysql_socket_close(new_sock); - } - delete thd; - set_current_thd(0); - statistic_increment(connection_errors_internal, &LOCK_status); - continue; - } +#if defined(_WIN32) || defined(HAVE_SMEM) + handle_connections_methods(); +#else + handle_connections_sockets(); +#endif /* _WIN32 || HAVE_SMEM */ - init_net_server_extension(thd); - if (is_unix_sock) - thd->security_ctx->host=(char*) my_localhost; + /* (void) pthread_attr_destroy(&connection_attrib); */ - if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) - { - thd->extra_port= 1; - thd->scheduler= extra_thread_scheduler; - } - create_new_thread(thd); - set_current_thd(0); - } - DBUG_VOID_RETURN; -} + DBUG_PRINT("quit",("Exiting main thread")); +#ifndef __WIN__ +#ifdef EXTRA_DEBUG2 + sql_print_error("Before Lock_thread_count"); +#endif +#ifdef WITH_WSREP + WSREP_DEBUG("Before Lock_thread_count"); +#endif + mysql_mutex_lock(&LOCK_thread_count); + DBUG_PRINT("quit", ("Got thread_count mutex")); + select_thread_in_use=0; // For close_connections + mysql_mutex_unlock(&LOCK_thread_count); + mysql_cond_broadcast(&COND_thread_count); +#ifdef EXTRA_DEBUG2 + sql_print_error("After lock_thread_count"); +#endif +#endif /* __WIN__ */ -#ifdef _WIN32 -pthread_handler_t handle_connections_sockets_thread(void *arg) -{ - my_thread_init(); - handle_connections_sockets(); - decrement_handler_count(); - return 0; -} +#ifdef HAVE_PSI_THREAD_INTERFACE + /* + Disable the main thread instrumentation, + to avoid recording events during the shutdown. + */ + PSI_THREAD_CALL(delete_current_thread)(); +#endif -pthread_handler_t handle_connections_namedpipes(void *arg) -{ - HANDLE hConnectedPipe; - OVERLAPPED connectOverlapped= {0}; - THD *thd; - my_thread_init(); - DBUG_ENTER("handle_connections_namedpipes"); - connectOverlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL); - if (!connectOverlapped.hEvent) + /* Wait until cleanup is done */ + mysql_mutex_lock(&LOCK_thread_count); + while (!ready_to_exit) + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); + +#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) + if (Service.IsNT() && start_mode) + Service.Stop(); + else { - sql_print_error("Can't create event, last error=%u", GetLastError()); - unireg_abort(1); + Service.SetShutdownEvent(0); + if (hEventShutdown) + CloseHandle(hEventShutdown); } - DBUG_PRINT("general",("Waiting for named pipe connections.")); - while (!abort_loop) - { - /* wait for named pipe connection */ - BOOL fConnected= ConnectNamedPipe(hPipe, &connectOverlapped); - if (!fConnected && (GetLastError() == ERROR_IO_PENDING)) - { - /* - ERROR_IO_PENDING says async IO has started but not yet finished. - GetOverlappedResult will wait for completion. - */ - DWORD bytes; - fConnected= GetOverlappedResult(hPipe, &connectOverlapped,&bytes, TRUE); - } - if (abort_loop) - break; - if (!fConnected) - fConnected = GetLastError() == ERROR_PIPE_CONNECTED; - if (!fConnected) - { - CloseHandle(hPipe); - if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX | - FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE | - PIPE_READMODE_BYTE | - PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - (int) global_system_variables. - net_buffer_length, - (int) global_system_variables. - net_buffer_length, - NMPWAIT_USE_DEFAULT_WAIT, - &saPipeSecurity)) == - INVALID_HANDLE_VALUE) - { - sql_perror("Can't create new named pipe!"); - break; // Abort - } - } - hConnectedPipe = hPipe; - /* create new pipe for new connection */ - if ((hPipe = CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX | - FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE | - PIPE_READMODE_BYTE | - PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - (int) global_system_variables.net_buffer_length, - (int) global_system_variables.net_buffer_length, - NMPWAIT_USE_DEFAULT_WAIT, - &saPipeSecurity)) == - INVALID_HANDLE_VALUE) - { - sql_perror("Can't create new named pipe!"); - hPipe=hConnectedPipe; - continue; // We have to try again - } - - if (!(thd = new THD)) - { - DisconnectNamedPipe(hConnectedPipe); - CloseHandle(hConnectedPipe); - continue; - } - set_current_thd(thd); - if (!(thd->net.vio= vio_new_win32pipe(hConnectedPipe)) || - my_net_init(&thd->net, thd->net.vio, MYF(MY_THREAD_SPECIFIC))) - { -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#else - close_connection(thd, ER_OUT_OF_RESOURCES); #endif - delete thd; - set_current_thd(0); - continue; - } - /* Host is unknown */ - thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); - create_new_thread(thd); - set_current_thd(0); - } - CloseHandle(connectOverlapped.hEvent); - DBUG_LEAVE; - decrement_handler_count(); + mysqld_exit(0); return 0; } -#endif /* _WIN32 */ +#endif /* !EMBEDDED_LIBRARY */ -#ifdef HAVE_SMEM -/** - Thread of shared memory's service. +/**************************************************************************** + Main and thread entry function for Win32 + (all this is needed only to run mysqld as a service on WinNT) +****************************************************************************/ - @param arg Arguments of thread -*/ -pthread_handler_t handle_connections_shared_memory(void *arg) +#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) +int mysql_service(void *p) { - /* file-mapping object, use for create shared memory */ - HANDLE handle_connect_file_map= 0; - char *handle_connect_map= 0; // pointer on shared memory - HANDLE event_connect_answer= 0; - ulong smem_buffer_length= shared_memory_buffer_length + 4; - ulong connect_number= 1; - char *tmp= NULL; - char *suffix_pos; - char connect_number_char[22], *p; - const char *errmsg= 0; - SECURITY_ATTRIBUTES *sa_event= 0, *sa_mapping= 0; - my_thread_init(); - DBUG_ENTER("handle_connections_shared_memorys"); - DBUG_PRINT("general",("Waiting for allocated shared memory.")); + if (my_thread_init()) + return 1; + + if (use_opt_args) + win_main(opt_argc, opt_argv); + else + win_main(Service.my_argc, Service.my_argv); - /* - get enough space base-name + '_' + longest suffix we might ever send - */ - if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L, MYF(MY_FAE)))) - goto error; + my_thread_end(); + return 0; +} - if (my_security_attr_create(&sa_event, &errmsg, - GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE)) - goto error; - if (my_security_attr_create(&sa_mapping, &errmsg, - GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE)) - goto error; +/* Quote string if it contains space, else copy */ - /* - The name of event and file-mapping events create agree next rule: - shared_memory_base_name+unique_part - Where: - shared_memory_base_name is unique value for each server - unique_part is unique value for each object (events and file-mapping) - */ - suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS); - strmov(suffix_pos, "CONNECT_REQUEST"); - if ((smem_event_connect_request= CreateEvent(sa_event, - FALSE, FALSE, tmp)) == 0) +static char *add_quoted_string(char *to, const char *from, char *to_end) +{ + uint length= (uint) (to_end-to); + + if (!strchr(from, ' ')) + return strmake(to, from, length-1); + return strxnmov(to, length-1, "\"", from, "\"", NullS); +} + + +/** + Handle basic handling of services, like installation and removal. + + @param argv Pointer to argument list + @param servicename Internal name of service + @param displayname Display name of service (in taskbar ?) + @param file_path Path to this program + @param startup_option Startup option to mysqld + + @retval 0 option handled + @retval 1 Could not handle option +*/ + +static bool +default_service_handling(char **argv, + const char *servicename, + const char *displayname, + const char *file_path, + const char *extra_opt, + const char *account_name) +{ + char path_and_service[FN_REFLEN+FN_REFLEN+32], *pos, *end; + const char *opt_delim; + end= path_and_service + sizeof(path_and_service)-3; + + /* We have to quote filename if it contains spaces */ + pos= add_quoted_string(path_and_service, file_path, end); + if (*extra_opt) { - errmsg= "Could not create request event"; - goto error; + /* + Add option after file_path. There will be zero or one extra option. It's + assumed to be --defaults-file=file but isn't checked. The variable (not + the option name) should be quoted if it contains a string. + */ + *pos++= ' '; + if (opt_delim= strchr(extra_opt, '=')) + { + size_t length= ++opt_delim - extra_opt; + pos= strnmov(pos, extra_opt, length); + } + else + opt_delim= extra_opt; + + pos= add_quoted_string(pos, opt_delim, end); } - strmov(suffix_pos, "CONNECT_ANSWER"); - if ((event_connect_answer= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) + /* We must have servicename last */ + *pos++= ' '; + (void) add_quoted_string(pos, servicename, end); + + if (Service.got_service_option(argv, "install")) { - errmsg="Could not create answer event"; - goto error; + Service.Install(1, servicename, displayname, path_and_service, + account_name); + return 0; } - strmov(suffix_pos, "CONNECT_DATA"); - if ((handle_connect_file_map= - CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping, - PAGE_READWRITE, 0, sizeof(connect_number), tmp)) == 0) + if (Service.got_service_option(argv, "install-manual")) { - errmsg= "Could not create file mapping"; - goto error; + Service.Install(0, servicename, displayname, path_and_service, + account_name); + return 0; } - if ((handle_connect_map= (char *)MapViewOfFile(handle_connect_file_map, - FILE_MAP_WRITE,0,0, - sizeof(DWORD))) == 0) + if (Service.got_service_option(argv, "remove")) { - errmsg= "Could not create shared memory service"; - goto error; + Service.Remove(servicename); + return 0; } + return 1; +} - while (!abort_loop) - { - /* Wait a request from client */ - WaitForSingleObject(smem_event_connect_request,INFINITE); - /* - it can be after shutdown command - */ - if (abort_loop) - goto error; +int mysqld_main(int argc, char **argv) +{ + my_progname= argv[0]; - HANDLE handle_client_file_map= 0; - char *handle_client_map= 0; - HANDLE event_client_wrote= 0; - HANDLE event_client_read= 0; // for transfer data server <-> client - HANDLE event_server_wrote= 0; - HANDLE event_server_read= 0; - HANDLE event_conn_closed= 0; - THD *thd= 0; + /* + When several instances are running on the same machine, we + need to have an unique named hEventShudown through the + application PID e.g.: MySQLShutdown1890; MySQLShutdown2342 + */ + int10_to_str((int) GetCurrentProcessId(),strmov(shutdown_event_name, + "MySQLShutdown"), 10); - p= int10_to_str(connect_number, connect_number_char, 10); - /* - The name of event and file-mapping events create agree next rule: - shared_memory_base_name+unique_part+number_of_connection - Where: - shared_memory_base_name is uniquel value for each server - unique_part is unique value for each object (events and file-mapping) - number_of_connection is connection-number between server and client - */ - suffix_pos= strxmov(tmp,shared_memory_base_name,"_",connect_number_char, - "_",NullS); - strmov(suffix_pos, "DATA"); - if ((handle_client_file_map= - CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping, - PAGE_READWRITE, 0, smem_buffer_length, tmp)) == 0) + /* Must be initialized early for comparison of service name */ + system_charset_info= &my_charset_utf8_general_ci; + + if (my_init()) + { + fprintf(stderr, "my_init() failed."); + return 1; + } + + if (Service.GetOS()) /* true NT family */ + { + char file_path[FN_REFLEN]; + my_path(file_path, argv[0], ""); /* Find name in path */ + fn_format(file_path,argv[0],file_path,"", + MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS); + + if (argc == 2) { - errmsg= "Could not create file mapping"; - goto errorconn; + if (!default_service_handling(argv, MYSQL_SERVICENAME, MYSQL_SERVICENAME, + file_path, "", NULL)) + return 0; + if (Service.IsService(argv[1])) /* Start an optional service */ + { + /* + Only add the service name to the groups read from the config file + if it's not "MySQL". (The default service name should be 'mysqld' + but we started a bad tradition by calling it MySQL from the start + and we are now stuck with it. + */ + if (my_strcasecmp(system_charset_info, argv[1],"mysql")) + load_default_groups[load_default_groups_sz-2]= argv[1]; + start_mode= 1; + Service.Init(argv[1], mysql_service); + return 0; + } } - if ((handle_client_map= (char*)MapViewOfFile(handle_client_file_map, - FILE_MAP_WRITE,0,0, - smem_buffer_length)) == 0) + else if (argc == 3) /* install or remove any optional service */ { - errmsg= "Could not create memory map"; - goto errorconn; + if (!default_service_handling(argv, argv[2], argv[2], file_path, "", + NULL)) + return 0; + if (Service.IsService(argv[2])) + { + /* + mysqld was started as + mysqld --defaults-file=my_path\my.ini service-name + */ + use_opt_args=1; + opt_argc= 2; // Skip service-name + opt_argv=argv; + start_mode= 1; + if (my_strcasecmp(system_charset_info, argv[2],"mysql")) + load_default_groups[load_default_groups_sz-2]= argv[2]; + Service.Init(argv[2], mysql_service); + return 0; + } } - strmov(suffix_pos, "CLIENT_WROTE"); - if ((event_client_wrote= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) + else if (argc == 4 || argc == 5) { - errmsg= "Could not create client write event"; - goto errorconn; + /* + This may seem strange, because we handle --local-service while + preserving 4.1's behavior of allowing any one other argument that is + passed to the service on startup. (The assumption is that this is + --defaults-file=file, but that was not enforced in 4.1, so we don't + enforce it here.) + */ + const char *extra_opt= NullS; + const char *account_name = NullS; + int index; + for (index = 3; index < argc; index++) + { + if (!strcmp(argv[index], "--local-service")) + account_name= "NT AUTHORITY\\LocalService"; + else + extra_opt= argv[index]; + } + + if (argc == 4 || account_name) + if (!default_service_handling(argv, argv[2], argv[2], file_path, + extra_opt, account_name)) + return 0; } - strmov(suffix_pos, "CLIENT_READ"); - if ((event_client_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) + else if (argc == 1 && Service.IsService(MYSQL_SERVICENAME)) { - errmsg= "Could not create client read event"; - goto errorconn; - } - strmov(suffix_pos, "SERVER_READ"); - if ((event_server_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) - { - errmsg= "Could not create server read event"; - goto errorconn; - } - strmov(suffix_pos, "SERVER_WROTE"); - if ((event_server_wrote= CreateEvent(sa_event, - FALSE, FALSE, tmp)) == 0) - { - errmsg= "Could not create server write event"; - goto errorconn; - } - strmov(suffix_pos, "CONNECTION_CLOSED"); - if ((event_conn_closed= CreateEvent(sa_event, - TRUE, FALSE, tmp)) == 0) - { - errmsg= "Could not create closed connection event"; - goto errorconn; - } - if (abort_loop) - goto errorconn; - if (!(thd= new THD)) - goto errorconn; - /* Send number of connection to client */ - int4store(handle_connect_map, connect_number); - if (!SetEvent(event_connect_answer)) - { - errmsg= "Could not send answer event"; - goto errorconn; - } - /* Set event that client should receive data */ - if (!SetEvent(event_client_read)) - { - errmsg= "Could not set client to read mode"; - goto errorconn; + /* start the default service */ + start_mode= 1; + Service.Init(MYSQL_SERVICENAME, mysql_service); + return 0; } - set_current_thd(thd); - if (!(thd->net.vio= vio_new_win32shared_memory(handle_client_file_map, - handle_client_map, - event_client_wrote, - event_client_read, - event_server_wrote, - event_server_read, - event_conn_closed)) || - my_net_init(&thd->net, thd->net.vio, MYF(MY_THREAD_SPECIFIC))) - { -#ifdef WITH_WSREP - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#else - close_connection(thd, ER_OUT_OF_RESOURCES); + } + /* Start as standalone server */ + Service.my_argc=argc; + Service.my_argv=argv; + mysql_service(NULL); + return 0; +} #endif - errmsg= 0; - goto errorconn; - } - thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); /* Host is unknown */ - create_new_thread(thd); - connect_number++; - set_current_thd(thd); - continue; -errorconn: - /* Could not form connection; Free used handlers/memort and retry */ - if (errmsg) - { - char buff[180]; - strxmov(buff, "Can't create shared memory connection: ", errmsg, ".", - NullS); - sql_perror(buff); - } - if (handle_client_file_map) - CloseHandle(handle_client_file_map); - if (handle_client_map) - UnmapViewOfFile(handle_client_map); - if (event_server_wrote) - CloseHandle(event_server_wrote); - if (event_server_read) - CloseHandle(event_server_read); - if (event_client_wrote) - CloseHandle(event_client_wrote); - if (event_client_read) - CloseHandle(event_client_read); - if (event_conn_closed) - CloseHandle(event_conn_closed); - delete thd; - } - set_current_thd(0); - /* End shared memory handling */ -error: - if (tmp) - my_free(tmp); +/** + Execute all commands from a file. Used by the mysql_install_db script to + create MySQL privilege tables without having to start a full MySQL server. +*/ - if (errmsg) +static void bootstrap(MYSQL_FILE *file) +{ + DBUG_ENTER("bootstrap"); + + THD *thd= new THD; +#ifdef WITH_WSREP + thd->variables.wsrep_on= 0; +#endif + thd->bootstrap=1; + my_net_init(&thd->net,(st_vio*) 0, MYF(0)); + thd->max_client_packet_length= thd->net.max_packet; + thd->security_ctx->master_access= ~(ulong)0; + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; + thread_count++; // Safe as only one thread running + in_bootstrap= TRUE; + + bootstrap_file=file; +#ifndef EMBEDDED_LIBRARY // TODO: Enable this + if (mysql_thread_create(key_thread_bootstrap, + &thd->real_id, &connection_attrib, handle_bootstrap, + (void*) thd)) { - char buff[180]; - strxmov(buff, "Can't create shared memory service: ", errmsg, ".", NullS); - sql_perror(buff); + sql_print_warning("Can't create thread to handle bootstrap"); + bootstrap_error=-1; + DBUG_VOID_RETURN; } - my_security_attr_free(sa_event); - my_security_attr_free(sa_mapping); - if (handle_connect_map) UnmapViewOfFile(handle_connect_map); - if (handle_connect_file_map) CloseHandle(handle_connect_file_map); - if (event_connect_answer) CloseHandle(event_connect_answer); - if (smem_event_connect_request) CloseHandle(smem_event_connect_request); - DBUG_LEAVE; - decrement_handler_count(); - return 0; + /* Wait for thread to die */ + mysql_mutex_lock(&LOCK_thread_count); + while (in_bootstrap) + { + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); + DBUG_PRINT("quit",("One thread died (count=%u)",thread_count)); + } + mysql_mutex_unlock(&LOCK_thread_count); +#else + thd->mysql= 0; + do_handle_bootstrap(thd); +#endif + + DBUG_VOID_RETURN; } -#endif /* HAVE_SMEM */ -#endif /* EMBEDDED_LIBRARY */ -/**************************************************************************** - Handle start options -******************************************************************************/ +static bool read_init_file(char *file_name) +{ + MYSQL_FILE *file; + DBUG_ENTER("read_init_file"); + DBUG_PRINT("enter",("name: %s",file_name)); + if (!(file= mysql_file_fopen(key_file_init, file_name, + O_RDONLY, MYF(MY_WME)))) + DBUG_RETURN(TRUE); + bootstrap(file); + mysql_file_fclose(file, MYF(MY_WME)); + DBUG_RETURN(FALSE); +} /** - Process command line options flagged as 'early'. - Some components needs to be initialized as early as possible, - because the rest of the server initialization depends on them. - Options that needs to be parsed early includes: - - the performance schema, when compiled in, - - options related to the help, - - options related to the bootstrap - The performance schema needs to be initialized as early as possible, - before to-be-instrumented objects of the server are initialized. + Increment number of created threads */ - -int handle_early_options() +void inc_thread_created(void) { - int ho_error; - DYNAMIC_ARRAY all_early_options; + thread_created++; +} - my_getopt_register_get_addr(NULL); - /* Skip unknown options so that they may be processed later */ - my_getopt_skip_unknown= TRUE; +#ifndef EMBEDDED_LIBRARY - /* prepare all_early_options array */ - my_init_dynamic_array(&all_early_options, sizeof(my_option), 100, 25, MYF(0)); - add_many_options(&all_early_options, pfs_early_options, - array_elements(pfs_early_options)); - sys_var_add_options(&all_early_options, sys_var::PARSE_EARLY); - add_terminator(&all_early_options); +/* + Simple scheduler that use the main thread to handle the request - ho_error= handle_options(&remaining_argc, &remaining_argv, - (my_option*)(all_early_options.buffer), - mysqld_get_one_option); - if (ho_error == 0) - { - /* Add back the program name handle_options removes */ - remaining_argc++; - remaining_argv--; - } + NOTES + This is only used for debugging, when starting mysqld with + --thread-handling=no-threads or --one-thread - delete_dynamic(&all_early_options); + When we enter this function, LOCK_thread_count is hold! +*/ - return ho_error; +void handle_connection_in_main_thread(THD *thd) +{ + mysql_mutex_assert_owner(&LOCK_thread_count); + thread_cache_size=0; // Safety + threads.append(thd); + mysql_mutex_unlock(&LOCK_thread_count); + thd->start_utime= microsecond_interval_timer(); + do_handle_one_connection(thd); } -/** - System variables are automatically command-line options (few - exceptions are documented in sys_var.h), so don't need - to be listed here. +/* + Scheduler that uses one thread per connection */ -struct my_option my_long_options[]= +void create_thread_to_handle_connection(THD *thd) { - {"help", '?', "Display this help and exit.", - &opt_help, &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, - 0, 0}, - {"allow-suspicious-udfs", 0, - "Allows use of UDFs consisting of only one symbol xxx() " - "without corresponding xxx_init() or xxx_deinit(). That also means " - "that one can load any function from any library, for example exit() " - "from libc.so", - &opt_allow_suspicious_udfs, &opt_allow_suspicious_udfs, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode " - "will also set transaction isolation level 'serializable'.", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - /* - Because Sys_var_bit does not support command-line options, we need to - explicitely add one for --autocommit - */ - {"autocommit", 0, "Set default value for autocommit (0 or 1)", - &opt_autocommit, &opt_autocommit, 0, - GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, NULL}, - {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.", - &my_bind_addr_str, &my_bind_addr_str, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"binlog-do-db", OPT_BINLOG_DO_DB, - "Tells the master it should log updates for the specified database, " - "and exclude all others not explicitly mentioned.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, - "Tells the master that updates to the given database should not be logged to the binary log.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"binlog-row-event-max-size", 0, - "The maximum size of a row-based binary log event in bytes. Rows will be " - "grouped into events smaller than this size if possible. " - "The value has to be a multiple of 256.", - &opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size, - 0, GET_ULONG, REQUIRED_ARG, - /* def_value */ 1024, /* min_value */ 256, /* max_value */ ULONG_MAX, - /* sub_size */ 0, /* block_size */ 256, - /* app_type */ 0 - }, -#ifndef DISABLE_GRANT_OPTIONS - {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"character-set-client-handshake", 0, - "Don't ignore client side character set value sent during handshake.", - &opt_character_set_client_handshake, - &opt_character_set_client_handshake, - 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"character-set-filesystem", 0, - "Set the filesystem character set.", - &character_set_filesystem_name, - &character_set_filesystem_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - {"character-set-server", 'C', "Set the default character set.", - &default_character_set_name, &default_character_set_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - {"chroot", 'r', "Chroot mysqld daemon during startup.", - &mysqld_chroot, &mysqld_chroot, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0}, - {"collation-server", 0, "Set the default collation.", - &default_collation_name, &default_collation_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - {"console", OPT_CONSOLE, "Write error output on screen; don't remove the console window on windows.", - &opt_console, &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0, - 0, 0, 0}, - {"core-file", OPT_WANT_CORE, "Write core on errors.", 0, 0, 0, GET_NO_ARG, - NO_ARG, 0, 0, 0, 0, 0, 0}, - /* default-storage-engine should have "MyISAM" as def_value. Instead - of initializing it here it is done in init_common_variables() due - to a compiler bug in Sun Studio compiler. */ -#ifdef DBUG_OFF - {"debug", '#', "Built in DBUG debugger. Disabled in this build.", - ¤t_dbug_option, ¤t_dbug_option, 0, GET_STR, OPT_ARG, - 0, 0, 0, 0, 0, 0}, -#endif -#ifdef HAVE_REPLICATION - {"debug-abort-slave-event-count", 0, - "Option used by mysql-test for debugging and testing of replication.", - &abort_slave_event_count, &abort_slave_event_count, - 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif /* HAVE_REPLICATION */ -#ifndef DBUG_OFF - {"debug-assert-on-error", 0, - "Do an assert in various functions if we get a fatal error", - &my_assert_on_error, &my_assert_on_error, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"debug-assert-if-crashed-table", 0, - "Do an assert in handler::print_error() if we get a crashed table", - &debug_assert_if_crashed_table, &debug_assert_if_crashed_table, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif -#ifdef HAVE_REPLICATION - {"debug-disconnect-slave-event-count", 0, - "Option used by mysql-test for debugging and testing of replication.", - &disconnect_slave_event_count, &disconnect_slave_event_count, - 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif /* HAVE_REPLICATION */ - {"debug-exit-info", 'T', "Used for debugging. Use at your own risk.", - 0, 0, 0, GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"debug-gdb", 0, - "Set up signals usable for debugging.", - &opt_debugging, &opt_debugging, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef HAVE_REPLICATION - {"debug-max-binlog-dump-events", 0, - "Option used by mysql-test for debugging and testing of replication.", - &max_binlog_dump_events, &max_binlog_dump_events, 0, - GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif /* HAVE_REPLICATION */ -#ifdef SAFE_MUTEX - {"debug-mutex-deadlock-detector", 0, - "Enable checking of wrong mutex usage.", - &safe_mutex_deadlock_detector, - &safe_mutex_deadlock_detector, - 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, -#endif - {"debug-no-sync", 0, - "Disables system sync calls. Only for running tests or debugging!", - &my_disable_sync, &my_disable_sync, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef HAVE_REPLICATION - {"debug-sporadic-binlog-dump-fail", 0, - "Option used by mysql-test for debugging and testing of replication.", - &opt_sporadic_binlog_dump_fail, - &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, - 0}, -#endif /* HAVE_REPLICATION */ - {"default-storage-engine", 0, "The default storage engine for new tables", - &default_storage_engine, 0, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0 }, - {"default-time-zone", 0, "Set the default time zone.", - &default_tz_name, &default_tz_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#if defined(ENABLED_DEBUG_SYNC) - {"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT, - "Enable the debug sync facility " - "and optionally specify a default wait timeout in seconds. " - "A zero value keeps the facility disabled.", - &opt_debug_sync_timeout, 0, - 0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0}, -#endif /* defined(ENABLED_DEBUG_SYNC) */ -#ifdef HAVE_OPENSSL - {"des-key-file", 0, - "Load keys for des_encrypt() and des_encrypt from given file.", - &des_key_file, &des_key_file, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0}, -#endif /* HAVE_OPENSSL */ -#ifdef HAVE_STACKTRACE - {"stack-trace", 0 , "Print a symbolic stack trace on failure", - &opt_stack_trace, &opt_stack_trace, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, -#endif /* HAVE_STACKTRACE */ - {"external-locking", 0, "Use system (external) locking (disabled by " - "default). With this option enabled you can run myisamchk to test " - "(not repair) tables while the MySQL server is running. Disable with " - "--skip-external-locking.", &opt_external_locking, &opt_external_locking, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - /* We must always support the next option to make scripts like mysqltest - easier to do */ - {"gdb", 0, - "Set up signals usable for debugging. Deprecated, use --debug-gdb instead.", - &opt_debugging, &opt_debugging, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef HAVE_LARGE_PAGE_OPTION - {"super-large-pages", 0, "Enable support for super large pages.", - &opt_super_large_pages, &opt_super_large_pages, 0, - GET_BOOL, OPT_ARG, 0, 0, 1, 0, 1, 0}, -#endif - {"language", 'L', - "Client error messages in given language. May be given as a full path. " - "Deprecated. Use --lc-messages-dir instead.", - 0, 0, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"lc-messages", 0, - "Set the language used for the error messages.", - &lc_messages, &lc_messages, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0 }, - {"lc-time-names", 0, - "Set the language used for the month names and the days of the week.", - &lc_time_names_name, &lc_time_names_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - {"log-basename", OPT_LOG_BASENAME, - "Basename for all log files and the .pid file. This sets all log file " - "names at once (in 'datadir') and is normally the only option you need " - "for specifying log files. Sets names for --log-bin, --log-bin-index, " - "--relay-log, --relay-log-index, --general-log-file, " - "--log-slow-query-log-file, --log-error-file, and --pid-file", - &opt_log_basename, &opt_log_basename, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0}, - {"log-bin", OPT_BIN_LOG, - "Log update queries in binary format. Optional argument should be name for " - "binary log. If not given " - "'datadir'/'log-basename'-bin or 'datadir'/mysql-bin will be used (the later if " - "--log-basename is not specified). We strongly recommend to use either " - "--log-basename or specify a filename to ensure that replication doesn't " - "stop if the real hostname of the computer changes.", - &opt_bin_logname, &opt_bin_logname, 0, GET_STR, - OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"log-bin-index", 0, - "File that holds the names for last binary log files.", - &opt_binlog_index_name, &opt_binlog_index_name, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"log-isam", OPT_ISAM_LOG, "Log all MyISAM changes to file.", - &myisam_log_filename, &myisam_log_filename, 0, GET_STR, - OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"log-short-format", 0, - "Don't log extra information to update and slow-query logs.", - &opt_short_log_format, &opt_short_log_format, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"log-slow-admin-statements", 0, - "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to " - "the slow log if it is open.", &opt_log_slow_admin_statements, - &opt_log_slow_admin_statements, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"log-slow-slave-statements", 0, - "Log slow statements executed by slave thread to the slow log if it is open.", - &opt_log_slow_slave_statements, &opt_log_slow_slave_statements, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"log-tc", 0, - "Path to transaction coordinator log (used for transactions that affect " - "more than one storage engine, when binary log is disabled).", - &opt_tc_log_file, &opt_tc_log_file, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef HAVE_MMAP - {"log-tc-size", 0, "Size of transaction coordinator log.", - &opt_tc_log_size, &opt_tc_log_size, 0, GET_ULONG, - REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, (ulonglong) ULONG_MAX, 0, - TC_LOG_PAGE_SIZE, 0}, -#endif - {"master-info-file", 0, - "The location and name of the file that remembers the master and where " - "the I/O replication thread is in the master's binlogs. Defaults to " - "master.info", - &master_info_file, &master_info_file, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"master-retry-count", 0, - "The number of tries the slave will make to connect to the master before giving up.", - &master_retry_count, &master_retry_count, 0, GET_ULONG, - REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0}, -#ifdef HAVE_REPLICATION - {"init-rpl-role", 0, "Set the replication role.", - &rpl_status, &rpl_status, &rpl_role_typelib, - GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif /* HAVE_REPLICATION */ - {"memlock", 0, "Lock mysqld in memory.", &locked_in_memory, - &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"old-style-user-limits", 0, - "Enable old-style user limits (before 5.0.3, user resources were counted " - "per each user+host vs. per account).", - &opt_old_style_user_limits, &opt_old_style_user_limits, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"port-open-timeout", 0, - "Maximum time in seconds to wait for the port to become free. " - "(Default: No wait).", &mysqld_port_timeout, &mysqld_port_timeout, 0, - GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"replicate-do-db", OPT_REPLICATE_DO_DB, - "Tells the slave thread to restrict replication to the specified database. " - "To specify more than one database, use the directive multiple times, " - "once for each database. Note that this will only work if you do not use " - "cross-database queries such as UPDATE some_db.some_table SET foo='bar' " - "while having selected a different or no database. If you need cross " - "database updates to work, make sure you have 3.23.28 or later, and use " - "replicate-wild-do-table=db_name.%.", - 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"replicate-do-table", OPT_REPLICATE_DO_TABLE, - "Tells the slave thread to restrict replication to the specified table. " - "To specify more than one table, use the directive multiple times, once " - "for each table. This will work for cross-database updates, in contrast " - "to replicate-do-db.", 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"replicate-ignore-db", OPT_REPLICATE_IGNORE_DB, - "Tells the slave thread to not replicate to the specified database. To " - "specify more than one database to ignore, use the directive multiple " - "times, once for each database. This option will not work if you use " - "cross database updates. If you need cross database updates to work, " - "make sure you have 3.23.28 or later, and use replicate-wild-ignore-" - "table=db_name.%. ", 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"replicate-ignore-table", OPT_REPLICATE_IGNORE_TABLE, - "Tells the slave thread to not replicate to the specified table. To specify " - "more than one table to ignore, use the directive multiple times, once for " - "each table. This will work for cross-database updates, in contrast to " - "replicate-ignore-db.", 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"replicate-rewrite-db", OPT_REPLICATE_REWRITE_DB, - "Updates to a database with a different name than the original. Example: " - "replicate-rewrite-db=master_db_name->slave_db_name.", - 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef HAVE_REPLICATION - {"replicate-same-server-id", 0, - "In replication, if set to 1, do not skip events having our server id. " - "Default value is 0 (to break infinite loops in circular replication). " - "Can't be set to 1 if --log-slave-updates is used.", - &replicate_same_server_id, &replicate_same_server_id, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"replicate-wild-do-table", OPT_REPLICATE_WILD_DO_TABLE, - "Tells the slave thread to restrict replication to the tables that match " - "the specified wildcard pattern. To specify more than one table, use the " - "directive multiple times, once for each table. This will work for cross-" - "database updates. Example: replicate-wild-do-table=foo%.bar% will " - "replicate only updates to tables in all databases that start with foo " - "and whose table names start with bar.", - 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"replicate-wild-ignore-table", OPT_REPLICATE_WILD_IGNORE_TABLE, - "Tells the slave thread to not replicate to the tables that match the " - "given wildcard pattern. To specify more than one table to ignore, use " - "the directive multiple times, once for each table. This will work for " - "cross-database updates. Example: replicate-wild-ignore-table=foo%.bar% " - "will not do updates to tables in databases that start with foo and whose " - "table names start with bar.", - 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing). Deprecated.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"safe-user-create", 0, - "Don't allow new user creation by the user who has no write privileges to the mysql.user table.", - &opt_safe_user_create, &opt_safe_user_create, 0, GET_BOOL, - NO_ARG, 0, 0, 0, 0, 0, 0}, - {"show-slave-auth-info", 0, - "Show user and password in SHOW SLAVE HOSTS on this master.", - &opt_show_slave_auth_info, &opt_show_slave_auth_info, 0, - GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-bdb", OPT_DEPRECATED_OPTION, - "Deprecated option; Exist only for compatiblity with old my.cnf files", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifndef DISABLE_GRANT_OPTIONS - {"skip-grant-tables", 0, - "Start without grant tables. This gives all users FULL ACCESS to all tables.", - &opt_noacl, &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, - 0}, -#endif - {"skip-host-cache", OPT_SKIP_HOST_CACHE, "Don't cache host names.", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-slave-start", 0, - "If set, slave is not autostarted.", &opt_skip_slave_start, - &opt_skip_slave_start, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) - {"slow-start-timeout", 0, - "Maximum number of milliseconds that the service control manager should wait " - "before trying to kill the windows service during startup" - "(Default: 15000).", &slow_start_timeout, &slow_start_timeout, 0, - GET_ULONG, REQUIRED_ARG, 15000, 0, 0, 0, 0, 0}, -#endif -#ifdef HAVE_OPENSSL - {"ssl", 0, - "Enable SSL for connection (automatically enabled if an ssl option is used).", - &opt_use_ssl, &opt_use_ssl, 0, GET_BOOL, OPT_ARG, 0, 0, 0, - 0, 0, 0}, -#endif -#ifdef __WIN__ - {"standalone", 0, - "Dummy option to start as a standalone program (NT).", 0, 0, 0, GET_NO_ARG, - NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"symbolic-links", 's', "Enable symbolic link support.", - &my_use_symdir, &my_use_symdir, 0, GET_BOOL, NO_ARG, - /* - The system call realpath() produces warnings under valgrind and - purify. These are not suppressed: instead we disable symlinks - option if compiled with valgrind support. - Also disable by default on Windows, due to high overhead for checking .sym - files. - */ - IF_VALGRIND(0,IF_WIN(0,1)), 0, 0, 0, 0, 0}, - {"sysdate-is-now", 0, - "Non-default option to alias SYSDATE() to NOW() to make it safe-replicable. " - "Since 5.0, SYSDATE() returns a `dynamic' value different for different " - "invocations, even within the same statement.", - &global_system_variables.sysdate_is_now, - 0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, - {"tc-heuristic-recover", 0, - "Decision to use in heuristic recover process. Possible values are COMMIT " - "or ROLLBACK.", &tc_heuristic_recover, &tc_heuristic_recover, - &tc_heuristic_recover_typelib, GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"temp-pool", 0, -#if (ENABLE_TEMP_POOL) - "Using this option will cause most temporary files created to use a small " - "set of names, rather than a unique name for each new file.", -#else - "This option is ignored on this OS.", -#endif - &use_temp_pool, &use_temp_pool, 0, GET_BOOL, NO_ARG, 1, - 0, 0, 0, 0, 0}, - {"transaction-isolation", 0, - "Default transaction isolation level.", - &global_system_variables.tx_isolation, - &global_system_variables.tx_isolation, &tx_isolation_typelib, - GET_ENUM, REQUIRED_ARG, ISO_REPEATABLE_READ, 0, 0, 0, 0, 0}, - {"transaction-read-only", 0, - "Default transaction access mode. " - "True if transactions are read-only.", - &global_system_variables.tx_read_only, - &global_system_variables.tx_read_only, 0, - GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Used with --help option for detailed help.", - &opt_verbose, &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, - NO_ARG, 0, 0, 0, 0, 0, 0}, - {"plugin-load", OPT_PLUGIN_LOAD, - "Semicolon-separated list of plugins to load, where each plugin is " - "specified as ether a plugin_name=library_file pair or only a library_file. " - "If the latter case, all plugins from a given library_file will be loaded.", - 0, 0, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"plugin-load-add", OPT_PLUGIN_LOAD_ADD, - "Optional semicolon-separated list of plugins to load. This option adds " - "to the list speficied by --plugin-load in an incremental way. " - "It can be specified many times, adding more plugins every time.", - 0, 0, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"table_cache", 0, "Deprecated; use --table-open-cache instead.", - &tc_size, &tc_size, 0, GET_ULONG, - REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0} -}; + DBUG_ENTER("create_thread_to_handle_connection"); + mysql_mutex_assert_owner(&LOCK_thread_count); + + /* Check if we can get thread from the cache */ + if (cached_thread_count > wake_thread) + { + mysql_mutex_lock(&LOCK_thread_cache); + /* Recheck condition when we have the lock */ + if (cached_thread_count > wake_thread) + { + mysql_mutex_unlock(&LOCK_thread_count); + /* Get thread from cache */ + thread_cache.push_back(thd); + wake_thread++; + mysql_cond_signal(&COND_thread_cache); + mysql_mutex_unlock(&LOCK_thread_cache); + DBUG_PRINT("info",("Thread created")); + DBUG_VOID_RETURN; + } + mysql_mutex_unlock(&LOCK_thread_cache); + } -static int show_queries(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONGLONG; - var->value= (char *)&thd->query_id; - return 0; -} + char error_message_buff[MYSQL_ERRMSG_SIZE]; + /* Create new thread to handle connection */ + int error; + thread_created++; + threads.append(thd); + DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); + thd->prior_thr_create_utime= microsecond_interval_timer(); + if ((error= mysql_thread_create(key_thread_one_connection, + &thd->real_id, &connection_attrib, + handle_one_connection, + (void*) thd))) + { + /* purecov: begin inspected */ + DBUG_PRINT("error", + ("Can't create thread to handle request (error %d)", + error)); + thd->killed= KILL_CONNECTION; // Safety + mysql_mutex_unlock(&LOCK_thread_count); + mysql_mutex_lock(&LOCK_connection_count); + (*thd->scheduler->connection_count)--; + mysql_mutex_unlock(&LOCK_connection_count); -static int show_net_compression(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_MY_BOOL; - var->value= (char *)&thd->net.compress; - return 0; -} + statistic_increment(aborted_connects,&LOCK_status); + statistic_increment(connection_errors_internal, &LOCK_status); + /* Can't use my_error() since store_globals has not been called. */ + my_snprintf(error_message_buff, sizeof(error_message_buff), + ER_THD(thd, ER_CANT_CREATE_THREAD), error); + net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, NULL); +#ifdef WITH_WSREP + close_connection(thd, ER_OUT_OF_RESOURCES ,0); +#else + close_connection(thd, ER_OUT_OF_RESOURCES); +#endif /* WITH_WSREP */ -static int show_starttime(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (long) (thd->query_start() - server_start_time); - return 0; + mysql_mutex_lock(&LOCK_thread_count); + thd->unlink(); + mysql_mutex_unlock(&LOCK_thread_count); + delete thd; + thread_safe_decrement32(&thread_count, &thread_count_lock); + return; + /* purecov: end */ + } + mysql_mutex_unlock(&LOCK_thread_count); + DBUG_PRINT("info",("Thread created")); + DBUG_VOID_RETURN; } -#ifdef ENABLED_PROFILING -static int show_flushstatustime(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (long) (thd->query_start() - flush_status_time); - return 0; -} -#endif -#ifdef HAVE_REPLICATION -static int show_rpl_status(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_CHAR; - var->value= const_cast(rpl_status_type[(int)rpl_status]); - return 0; -} +/** + Create new thread to handle incoming connection. -static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff) -{ - Master_info *mi= NULL; - bool tmp; - LINT_INIT(tmp); + This function will create new thread to handle the incoming + connection. If there are idle cached threads one will be used. + 'thd' will be pushed into 'threads'. - var->type= SHOW_MY_BOOL; - var->value= buff; - mysql_mutex_unlock(&LOCK_status); - mysql_mutex_lock(&LOCK_active_mi); - if (master_info_index) - { - mi= master_info_index-> - get_master_info(&thd->variables.default_master_connection, - Sql_condition::WARN_LEVEL_NOTE); - if (mi) - tmp= (my_bool) (mi->slave_running == MYSQL_SLAVE_RUN_CONNECT && - mi->rli.slave_running); - } - mysql_mutex_unlock(&LOCK_active_mi); - mysql_mutex_lock(&LOCK_status); - if (mi) - *((my_bool *)buff)= tmp; - else - var->type= SHOW_UNDEF; - return 0; -} + In single-threaded mode (\#define ONE_THREAD) connection will be + handled inside this function. + @param[in,out] thd Thread handle of future thread. +*/ -static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff) +static void create_new_thread(THD *thd) { - Master_info *mi= NULL; - longlong tmp; - LINT_INIT(tmp); - - var->type= SHOW_LONGLONG; - var->value= buff; - mysql_mutex_unlock(&LOCK_status); - mysql_mutex_lock(&LOCK_active_mi); - if (master_info_index) - { - mi= master_info_index-> - get_master_info(&thd->variables.default_master_connection, - Sql_condition::WARN_LEVEL_NOTE); - if (mi) - tmp= mi->received_heartbeats; - } - mysql_mutex_unlock(&LOCK_active_mi); - mysql_mutex_lock(&LOCK_status); - if (mi) - *((longlong *)buff)= tmp; - else - var->type= SHOW_UNDEF; - return 0; -} + DBUG_ENTER("create_new_thread"); + /* + Don't allow too many connections. We roughly check here that we allow + only (max_connections + 1) connections. + */ -static int show_heartbeat_period(THD *thd, SHOW_VAR *var, char *buff) -{ - Master_info *mi= NULL; - float tmp; - LINT_INIT(tmp); + mysql_mutex_lock(&LOCK_connection_count); - var->type= SHOW_CHAR; - var->value= buff; - mysql_mutex_unlock(&LOCK_status); - mysql_mutex_lock(&LOCK_active_mi); - if (master_info_index) + if (*thd->scheduler->connection_count >= + *thd->scheduler->max_connections + 1|| abort_loop) { - mi= master_info_index-> - get_master_info(&thd->variables.default_master_connection, - Sql_condition::WARN_LEVEL_NOTE); - if (mi) - tmp= mi->heartbeat_period; + mysql_mutex_unlock(&LOCK_connection_count); + + DBUG_PRINT("error",("Too many connections")); +#ifdef WITH_WSREP + close_connection(thd, ER_CON_COUNT_ERROR, 1); +#else + close_connection(thd, ER_CON_COUNT_ERROR); +#endif /* WITH_WSREP */ + statistic_increment(denied_connections, &LOCK_status); + delete thd; + statistic_increment(connection_errors_max_connection, &LOCK_status); + DBUG_VOID_RETURN; } - mysql_mutex_unlock(&LOCK_active_mi); - mysql_mutex_lock(&LOCK_status); - if (mi) - sprintf(buff, "%.3f", tmp); - else - var->type= SHOW_UNDEF; - return 0; -} + ++*thd->scheduler->connection_count; -#endif /* HAVE_REPLICATION */ + if (connection_count + extra_connection_count > max_used_connections) + max_used_connections= connection_count + extra_connection_count; -static int show_open_tables(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *) buff)= (long) tc_records(); - return 0; -} + mysql_mutex_unlock(&LOCK_connection_count); -static int show_prepared_stmt_count(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - mysql_mutex_lock(&LOCK_prepared_stmt_count); - *((long *)buff)= (long)prepared_stmt_count; - mysql_mutex_unlock(&LOCK_prepared_stmt_count); - return 0; -} + thread_safe_increment32(&thread_count, &thread_count_lock); -static int show_table_definitions(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *) buff)= (long) tdc_records(); - return 0; + /* Start a new thread to handle connection. */ + mysql_mutex_lock(&LOCK_thread_count); + /* + The initialization of thread_id is done in create_embedded_thd() for + the embedded library. + TODO: refactor this to avoid code duplication there + */ + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; + + MYSQL_CALLBACK(thd->scheduler, add_connection, (thd)); + + DBUG_VOID_RETURN; } +#endif /* EMBEDDED_LIBRARY */ -static int show_flush_commands(THD *thd, SHOW_VAR *var, char *buff) +#ifdef SIGNALS_DONT_BREAK_READ +inline void kill_broken_server() { - var->type= SHOW_LONG; - var->value= buff; - *((long *) buff)= (long) tdc_refresh_version(); - return 0; + /* hack to get around signals ignored in syscalls for problem OS's */ + if (mysql_socket_getfd(unix_sock) == INVALID_SOCKET || + (!opt_disable_networking && + mysql_socket_getfd(base_ip_sock) == INVALID_SOCKET)) + { + select_thread_in_use = 0; + /* The following call will never return */ + DBUG_PRINT("general", ("killing server because socket is closed")); + kill_server((void*) MYSQL_KILL_SIGNAL); + } } +#define MAYBE_BROKEN_SYSCALL kill_broken_server(); +#else +#define MAYBE_BROKEN_SYSCALL +#endif + /* Handle new connections and spawn new process to handle them */ -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) -/* Functions relying on CTX */ -static int show_ssl_ctx_sess_accept(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context)); - return 0; -} +#ifndef EMBEDDED_LIBRARY -static int show_ssl_ctx_sess_accept_good(THD *thd, SHOW_VAR *var, char *buff) +void handle_connections_sockets() { - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context)); - return 0; -} + MYSQL_SOCKET sock= mysql_socket_invalid(); + MYSQL_SOCKET new_sock= mysql_socket_invalid(); + uint error_count=0; + THD *thd; + struct sockaddr_storage cAddr; + int ip_flags __attribute__((unused))=0; + int socket_flags __attribute__((unused))= 0; + int extra_ip_flags __attribute__((unused))=0; + int flags=0,retval; + st_vio *vio_tmp; + bool is_unix_sock; +#ifdef HAVE_POLL + int socket_count= 0; + struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock + MYSQL_SOCKET pfs_fds[3]; // for performance schema +#define setup_fds(X) \ + mysql_socket_set_thread_owner(X); \ + pfs_fds[socket_count]= (X); \ + fds[socket_count].fd= mysql_socket_getfd(X); \ + fds[socket_count].events= POLLIN; \ + socket_count++ +#else +#define setup_fds(X) FD_SET(mysql_socket_getfd(X),&clientFDs) + fd_set readFDs,clientFDs; + FD_ZERO(&clientFDs); +#endif -static int show_ssl_ctx_sess_connect_good(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context)); - return 0; -} + DBUG_ENTER("handle_connections_sockets"); -static int show_ssl_ctx_sess_accept_renegotiate(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)); - return 0; -} + if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET) + { + setup_fds(base_ip_sock); + ip_flags = fcntl(mysql_socket_getfd(base_ip_sock), F_GETFL, 0); + } + if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET) + { + setup_fds(extra_ip_sock); + extra_ip_flags = fcntl(mysql_socket_getfd(extra_ip_sock), F_GETFL, 0); + } +#ifdef HAVE_SYS_UN_H + setup_fds(unix_sock); + socket_flags=fcntl(mysql_socket_getfd(unix_sock), F_GETFL, 0); +#endif -static int show_ssl_ctx_sess_connect_renegotiate(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context)); - return 0; -} + DBUG_PRINT("general",("Waiting for connections.")); + MAYBE_BROKEN_SYSCALL; + while (!abort_loop) + { +#ifdef HAVE_POLL + retval= poll(fds, socket_count, -1); +#else + readFDs=clientFDs; + retval= select((int) 0,&readFDs,0,0,0); +#endif -static int show_ssl_ctx_sess_cb_hits(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context)); - return 0; -} + if (retval < 0) + { + if (socket_errno != SOCKET_EINTR) + { + /* + select(2)/poll(2) failed on the listening port. + There is not much details to report about the client, + increment the server global status variable. + */ + statistic_increment(connection_errors_accept, &LOCK_status); + if (!select_errors++ && !abort_loop) /* purecov: inspected */ + sql_print_error("mysqld: Got error %d from select",socket_errno); /* purecov: inspected */ + } + MAYBE_BROKEN_SYSCALL + continue; + } -static int show_ssl_ctx_sess_hits(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context)); - return 0; -} + if (abort_loop) + { + MAYBE_BROKEN_SYSCALL; + break; + } -static int show_ssl_ctx_sess_cache_full(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context)); - return 0; -} + /* Is this a new connection request ? */ +#ifdef HAVE_POLL + for (int i= 0; i < socket_count; ++i) + { + if (fds[i].revents & POLLIN) + { + sock= pfs_fds[i]; + flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0); + break; + } + } +#else // HAVE_POLL + if (FD_ISSET(mysql_socket_getfd(base_ip_sock),&readFDs)) + { + sock= base_ip_sock; + flags= ip_flags; + } + else + if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs)) + { + sock= extra_ip_sock; + flags= extra_ip_flags; + } + else + { + sock = unix_sock; + flags= socket_flags; + } +#endif // HAVE_POLL -static int show_ssl_ctx_sess_misses(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context)); - return 0; -} +#if !defined(NO_FCNTL_NONBLOCK) + if (!(test_flags & TEST_BLOCKING)) + { +#if defined(O_NONBLOCK) + fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK); +#elif defined(O_NDELAY) + fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY); +#endif + } +#endif /* NO_FCNTL_NONBLOCK */ + for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++) + { + size_socket length= sizeof(struct sockaddr_storage); + new_sock= mysql_socket_accept(key_socket_client_connection, sock, + (struct sockaddr *)(&cAddr), + &length); + if (mysql_socket_getfd(new_sock) != INVALID_SOCKET || + (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)) + break; + MAYBE_BROKEN_SYSCALL; +#if !defined(NO_FCNTL_NONBLOCK) + if (!(test_flags & TEST_BLOCKING)) + { + if (retry == MAX_ACCEPT_RETRY - 1) + { + // Try without O_NONBLOCK + fcntl(mysql_socket_getfd(sock), F_SETFL, flags); + } + } +#endif + } +#if !defined(NO_FCNTL_NONBLOCK) + if (!(test_flags & TEST_BLOCKING)) + fcntl(mysql_socket_getfd(sock), F_SETFL, flags); +#endif + if (mysql_socket_getfd(new_sock) == INVALID_SOCKET) + { + /* + accept(2) failed on the listening port, after many retries. + There is not much details to report about the client, + increment the server global status variable. + */ + statistic_increment(connection_errors_accept, &LOCK_status); + if ((error_count++ & 255) == 0) // This can happen often + sql_perror("Error in accept"); + MAYBE_BROKEN_SYSCALL; + if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE) + sleep(1); // Give other threads some time + continue; + } +#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC); +#endif /* WITH_WSREP */ -static int show_ssl_ctx_sess_timeouts(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)); - return 0; -} +#ifdef HAVE_LIBWRAP + { + if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) || + mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) + { + struct request_info req; + signal(SIGCHLD, SIG_DFL); + request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, + mysql_socket_getfd(new_sock), NULL); + my_fromhost(&req); + if (!my_hosts_access(&req)) + { + /* + This may be stupid but refuse() includes an exit(0) + which we surely don't want... + clean_exit() - same stupid thing ... + */ + syslog(deny_severity, "refused connect from %s", + my_eval_client(&req)); -static int show_ssl_ctx_sess_number(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)); - return 0; -} + /* + C++ sucks (the gibberish in front just translates the supplied + sink function pointer in the req structure from a void (*sink)(); + to a void(*sink)(int) if you omit the cast, the C++ compiler + will cry... + */ + if (req.sink) + ((void (*)(int))req.sink)(req.fd); -static int show_ssl_ctx_sess_connect(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)); - return 0; -} + (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); + (void) mysql_socket_close(new_sock); + /* + The connection was refused by TCP wrappers. + There are no details (by client IP) available to update the host_cache. + */ + statistic_increment(connection_tcpwrap_errors, &LOCK_status); + continue; + } + } + } +#endif /* HAVE_LIBWRAP */ -static int show_ssl_ctx_sess_get_cache_size(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)); - return 0; -} + /* + ** Don't allow too many connections + */ -static int show_ssl_ctx_get_verify_mode(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)); - return 0; -} + DBUG_PRINT("info", ("Creating THD for new connection")); + if (!(thd= new THD)) + { + (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); + (void) mysql_socket_close(new_sock); + statistic_increment(connection_errors_internal, &LOCK_status); + continue; + } + /* Set to get io buffers to be part of THD */ + set_current_thd(thd); -static int show_ssl_ctx_get_verify_depth(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - *((long *)buff)= (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)); - return 0; -} + is_unix_sock= (mysql_socket_getfd(sock) == + mysql_socket_getfd(unix_sock)); -static int show_ssl_ctx_get_session_cache_mode(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_CHAR; - if (!ssl_acceptor_fd) - var->value= const_cast("NONE"); - else - switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context)) + if (!(vio_tmp= + mysql_socket_vio_new(new_sock, + is_unix_sock ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, + is_unix_sock ? VIO_LOCALHOST: 0)) || + my_net_init(&thd->net, vio_tmp, MYF(MY_THREAD_SPECIFIC))) { - case SSL_SESS_CACHE_OFF: - var->value= const_cast("OFF"); break; - case SSL_SESS_CACHE_CLIENT: - var->value= const_cast("CLIENT"); break; - case SSL_SESS_CACHE_SERVER: - var->value= const_cast("SERVER"); break; - case SSL_SESS_CACHE_BOTH: - var->value= const_cast("BOTH"); break; - case SSL_SESS_CACHE_NO_AUTO_CLEAR: - var->value= const_cast("NO_AUTO_CLEAR"); break; - case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: - var->value= const_cast("NO_INTERNAL_LOOKUP"); break; - default: - var->value= const_cast("Unknown"); break; + /* + Only delete the temporary vio if we didn't already attach it to the + NET object. The destructor in THD will delete any initialized net + structure. + */ + if (vio_tmp && thd->net.vio != vio_tmp) + vio_delete(vio_tmp); + else + { + (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); + (void) mysql_socket_close(new_sock); + } + delete thd; + set_current_thd(0); + statistic_increment(connection_errors_internal, &LOCK_status); + continue; } - return 0; -} - -/* - Functions relying on SSL - Note: In the show_ssl_* functions, we need to check if we have a - valid vio-object since this isn't always true, specifically - when session_status or global_status is requested from - inside an Event. - */ -static int show_ssl_get_version(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_CHAR; - if( thd->vio_ok() && thd->net.vio->ssl_arg ) - var->value= const_cast(SSL_get_version((SSL*) thd->net.vio->ssl_arg)); - else - var->value= (char *)""; - return 0; -} -static int show_ssl_session_reused(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - if( thd->vio_ok() && thd->net.vio->ssl_arg ) - *((long *)buff)= (long)SSL_session_reused((SSL*) thd->net.vio->ssl_arg); - else - *((long *)buff)= 0; - return 0; -} + init_net_server_extension(thd); + if (is_unix_sock) + thd->security_ctx->host=(char*) my_localhost; -static int show_ssl_get_default_timeout(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - if( thd->vio_ok() && thd->net.vio->ssl_arg ) - *((long *)buff)= (long)SSL_get_default_timeout((SSL*)thd->net.vio->ssl_arg); - else - *((long *)buff)= 0; - return 0; + if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) + { + thd->extra_port= 1; + thd->scheduler= extra_thread_scheduler; + } + create_new_thread(thd); + set_current_thd(0); + } + DBUG_VOID_RETURN; } -static int show_ssl_get_verify_mode(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_LONG; - var->value= buff; - if( thd->net.vio && thd->net.vio->ssl_arg ) - *((long *)buff)= (long)SSL_get_verify_mode((SSL*)thd->net.vio->ssl_arg); - else - *((long *)buff)= 0; - return 0; -} -static int show_ssl_get_verify_depth(THD *thd, SHOW_VAR *var, char *buff) +#ifdef _WIN32 +pthread_handler_t handle_connections_sockets_thread(void *arg) { - var->type= SHOW_LONG; - var->value= buff; - if( thd->vio_ok() && thd->net.vio->ssl_arg ) - *((long *)buff)= (long)SSL_get_verify_depth((SSL*)thd->net.vio->ssl_arg); - else - *((long *)buff)= 0; + my_thread_init(); + handle_connections_sockets(); + decrement_handler_count(); return 0; } -static int show_ssl_get_cipher(THD *thd, SHOW_VAR *var, char *buff) +pthread_handler_t handle_connections_namedpipes(void *arg) { - var->type= SHOW_CHAR; - if( thd->vio_ok() && thd->net.vio->ssl_arg ) - var->value= const_cast(SSL_get_cipher((SSL*) thd->net.vio->ssl_arg)); - else - var->value= (char *)""; - return 0; -} + HANDLE hConnectedPipe; + OVERLAPPED connectOverlapped= {0}; + THD *thd; + my_thread_init(); + DBUG_ENTER("handle_connections_namedpipes"); + connectOverlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL); + if (!connectOverlapped.hEvent) + { + sql_print_error("Can't create event, last error=%u", GetLastError()); + unireg_abort(1); + } + DBUG_PRINT("general",("Waiting for named pipe connections.")); + while (!abort_loop) + { + /* wait for named pipe connection */ + BOOL fConnected= ConnectNamedPipe(hPipe, &connectOverlapped); + if (!fConnected && (GetLastError() == ERROR_IO_PENDING)) + { + /* + ERROR_IO_PENDING says async IO has started but not yet finished. + GetOverlappedResult will wait for completion. + */ + DWORD bytes; + fConnected= GetOverlappedResult(hPipe, &connectOverlapped,&bytes, TRUE); + } + if (abort_loop) + break; + if (!fConnected) + fConnected = GetLastError() == ERROR_PIPE_CONNECTED; + if (!fConnected) + { + CloseHandle(hPipe); + if ((hPipe= CreateNamedPipe(pipe_name, + PIPE_ACCESS_DUPLEX | + FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | + PIPE_READMODE_BYTE | + PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + (int) global_system_variables. + net_buffer_length, + (int) global_system_variables. + net_buffer_length, + NMPWAIT_USE_DEFAULT_WAIT, + &saPipeSecurity)) == + INVALID_HANDLE_VALUE) + { + sql_perror("Can't create new named pipe!"); + break; // Abort + } + } + hConnectedPipe = hPipe; + /* create new pipe for new connection */ + if ((hPipe = CreateNamedPipe(pipe_name, + PIPE_ACCESS_DUPLEX | + FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | + PIPE_READMODE_BYTE | + PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + (int) global_system_variables.net_buffer_length, + (int) global_system_variables.net_buffer_length, + NMPWAIT_USE_DEFAULT_WAIT, + &saPipeSecurity)) == + INVALID_HANDLE_VALUE) + { + sql_perror("Can't create new named pipe!"); + hPipe=hConnectedPipe; + continue; // We have to try again + } -static int show_ssl_get_cipher_list(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_CHAR; - var->value= buff; - if (thd->vio_ok() && thd->net.vio->ssl_arg) - { - int i; - const char *p; - char *end= buff + SHOW_VAR_FUNC_BUFF_SIZE; - for (i=0; (p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i)) && - buff < end; i++) + if (!(thd = new THD)) { - buff= strnmov(buff, p, end-buff-1); - *buff++= ':'; + DisconnectNamedPipe(hConnectedPipe); + CloseHandle(hConnectedPipe); + continue; } - if (i) - buff--; + set_current_thd(thd); + if (!(thd->net.vio= vio_new_win32pipe(hConnectedPipe)) || + my_net_init(&thd->net, thd->net.vio, MYF(MY_THREAD_SPECIFIC))) + { +#ifdef WITH_WSREP + close_connection(thd, ER_OUT_OF_RESOURCES, 1); +#else + close_connection(thd, ER_OUT_OF_RESOURCES); +#endif + delete thd; + set_current_thd(0); + continue; + } + /* Host is unknown */ + thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); + create_new_thread(thd); + set_current_thd(0); } - *buff=0; + CloseHandle(connectOverlapped.hEvent); + DBUG_LEAVE; + decrement_handler_count(); return 0; } +#endif /* _WIN32 */ -#ifdef HAVE_YASSL - -static char * -my_asn1_time_to_string(ASN1_TIME *time, char *buf, size_t len) -{ - return yaSSL_ASN1_TIME_to_string(time, buf, len); -} +#ifdef HAVE_SMEM -#else /* openssl */ +/** + Thread of shared memory's service. -static char * -my_asn1_time_to_string(ASN1_TIME *time, char *buf, size_t len) + @param arg Arguments of thread +*/ +pthread_handler_t handle_connections_shared_memory(void *arg) { - int n_read; - char *res= NULL; - BIO *bio= BIO_new(BIO_s_mem()); + /* file-mapping object, use for create shared memory */ + HANDLE handle_connect_file_map= 0; + char *handle_connect_map= 0; // pointer on shared memory + HANDLE event_connect_answer= 0; + ulong smem_buffer_length= shared_memory_buffer_length + 4; + ulong connect_number= 1; + char *tmp= NULL; + char *suffix_pos; + char connect_number_char[22], *p; + const char *errmsg= 0; + SECURITY_ATTRIBUTES *sa_event= 0, *sa_mapping= 0; + my_thread_init(); + DBUG_ENTER("handle_connections_shared_memorys"); + DBUG_PRINT("general",("Waiting for allocated shared memory.")); - if (bio == NULL) - return NULL; + /* + get enough space base-name + '_' + longest suffix we might ever send + */ + if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L, MYF(MY_FAE)))) + goto error; - if (!ASN1_TIME_print(bio, time)) - goto end; + if (my_security_attr_create(&sa_event, &errmsg, + GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE)) + goto error; - n_read= BIO_read(bio, buf, (int) (len - 1)); + if (my_security_attr_create(&sa_mapping, &errmsg, + GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE)) + goto error; - if (n_read > 0) + /* + The name of event and file-mapping events create agree next rule: + shared_memory_base_name+unique_part + Where: + shared_memory_base_name is unique value for each server + unique_part is unique value for each object (events and file-mapping) + */ + suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS); + strmov(suffix_pos, "CONNECT_REQUEST"); + if ((smem_event_connect_request= CreateEvent(sa_event, + FALSE, FALSE, tmp)) == 0) { - buf[n_read]= 0; - res= buf; + errmsg= "Could not create request event"; + goto error; + } + strmov(suffix_pos, "CONNECT_ANSWER"); + if ((event_connect_answer= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) + { + errmsg="Could not create answer event"; + goto error; + } + strmov(suffix_pos, "CONNECT_DATA"); + if ((handle_connect_file_map= + CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping, + PAGE_READWRITE, 0, sizeof(connect_number), tmp)) == 0) + { + errmsg= "Could not create file mapping"; + goto error; + } + if ((handle_connect_map= (char *)MapViewOfFile(handle_connect_file_map, + FILE_MAP_WRITE,0,0, + sizeof(DWORD))) == 0) + { + errmsg= "Could not create shared memory service"; + goto error; } -end: - BIO_free(bio); - return res; -} + while (!abort_loop) + { + /* Wait a request from client */ + WaitForSingleObject(smem_event_connect_request,INFINITE); + + /* + it can be after shutdown command + */ + if (abort_loop) + goto error; + + HANDLE handle_client_file_map= 0; + char *handle_client_map= 0; + HANDLE event_client_wrote= 0; + HANDLE event_client_read= 0; // for transfer data server <-> client + HANDLE event_server_wrote= 0; + HANDLE event_server_read= 0; + HANDLE event_conn_closed= 0; + THD *thd= 0; + p= int10_to_str(connect_number, connect_number_char, 10); + /* + The name of event and file-mapping events create agree next rule: + shared_memory_base_name+unique_part+number_of_connection + Where: + shared_memory_base_name is uniquel value for each server + unique_part is unique value for each object (events and file-mapping) + number_of_connection is connection-number between server and client + */ + suffix_pos= strxmov(tmp,shared_memory_base_name,"_",connect_number_char, + "_",NullS); + strmov(suffix_pos, "DATA"); + if ((handle_client_file_map= + CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping, + PAGE_READWRITE, 0, smem_buffer_length, tmp)) == 0) + { + errmsg= "Could not create file mapping"; + goto errorconn; + } + if ((handle_client_map= (char*)MapViewOfFile(handle_client_file_map, + FILE_MAP_WRITE,0,0, + smem_buffer_length)) == 0) + { + errmsg= "Could not create memory map"; + goto errorconn; + } + strmov(suffix_pos, "CLIENT_WROTE"); + if ((event_client_wrote= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) + { + errmsg= "Could not create client write event"; + goto errorconn; + } + strmov(suffix_pos, "CLIENT_READ"); + if ((event_client_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) + { + errmsg= "Could not create client read event"; + goto errorconn; + } + strmov(suffix_pos, "SERVER_READ"); + if ((event_server_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0) + { + errmsg= "Could not create server read event"; + goto errorconn; + } + strmov(suffix_pos, "SERVER_WROTE"); + if ((event_server_wrote= CreateEvent(sa_event, + FALSE, FALSE, tmp)) == 0) + { + errmsg= "Could not create server write event"; + goto errorconn; + } + strmov(suffix_pos, "CONNECTION_CLOSED"); + if ((event_conn_closed= CreateEvent(sa_event, + TRUE, FALSE, tmp)) == 0) + { + errmsg= "Could not create closed connection event"; + goto errorconn; + } + if (abort_loop) + goto errorconn; + if (!(thd= new THD)) + goto errorconn; + /* Send number of connection to client */ + int4store(handle_connect_map, connect_number); + if (!SetEvent(event_connect_answer)) + { + errmsg= "Could not send answer event"; + goto errorconn; + } + /* Set event that client should receive data */ + if (!SetEvent(event_client_read)) + { + errmsg= "Could not set client to read mode"; + goto errorconn; + } + set_current_thd(thd); + if (!(thd->net.vio= vio_new_win32shared_memory(handle_client_file_map, + handle_client_map, + event_client_wrote, + event_client_read, + event_server_wrote, + event_server_read, + event_conn_closed)) || + my_net_init(&thd->net, thd->net.vio, MYF(MY_THREAD_SPECIFIC))) + { +#ifdef WITH_WSREP + close_connection(thd, ER_OUT_OF_RESOURCES, 1); +#else + close_connection(thd, ER_OUT_OF_RESOURCES); #endif + errmsg= 0; + goto errorconn; + } + thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); /* Host is unknown */ + create_new_thread(thd); + connect_number++; + set_current_thd(thd); + continue; +errorconn: + /* Could not form connection; Free used handlers/memort and retry */ + if (errmsg) + { + char buff[180]; + strxmov(buff, "Can't create shared memory connection: ", errmsg, ".", + NullS); + sql_perror(buff); + } + if (handle_client_file_map) + CloseHandle(handle_client_file_map); + if (handle_client_map) + UnmapViewOfFile(handle_client_map); + if (event_server_wrote) + CloseHandle(event_server_wrote); + if (event_server_read) + CloseHandle(event_server_read); + if (event_client_wrote) + CloseHandle(event_client_wrote); + if (event_client_read) + CloseHandle(event_client_read); + if (event_conn_closed) + CloseHandle(event_conn_closed); + delete thd; + } + set_current_thd(0); -/** - Handler function for the 'ssl_get_server_not_before' variable - - @param thd the mysql thread structure - @param var the data for the variable - @param[out] buf the string to put the value of the variable into - - @return status - @retval 0 success -*/ + /* End shared memory handling */ +error: + if (tmp) + my_free(tmp); -static int -show_ssl_get_server_not_before(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_CHAR; - if(thd->vio_ok() && thd->net.vio->ssl_arg) + if (errmsg) { - SSL *ssl= (SSL*) thd->net.vio->ssl_arg; - X509 *cert= SSL_get_certificate(ssl); - ASN1_TIME *not_before= X509_get_notBefore(cert); - - var->value= my_asn1_time_to_string(not_before, buff, - SHOW_VAR_FUNC_BUFF_SIZE); - if (!var->value) - return 1; - var->value= buff; + char buff[180]; + strxmov(buff, "Can't create shared memory service: ", errmsg, ".", NullS); + sql_perror(buff); } - else - var->value= empty_c_string; + my_security_attr_free(sa_event); + my_security_attr_free(sa_mapping); + if (handle_connect_map) UnmapViewOfFile(handle_connect_map); + if (handle_connect_file_map) CloseHandle(handle_connect_file_map); + if (event_connect_answer) CloseHandle(event_connect_answer); + if (smem_event_connect_request) CloseHandle(smem_event_connect_request); + DBUG_LEAVE; + decrement_handler_count(); return 0; } +#endif /* HAVE_SMEM */ +#endif /* EMBEDDED_LIBRARY */ -/** - Handler function for the 'ssl_get_server_not_after' variable +/**************************************************************************** + Handle start options +******************************************************************************/ - @param thd the mysql thread structure - @param var the data for the variable - @param[out] buf the string to put the value of the variable into - @return status - @retval 0 success +/** + Process command line options flagged as 'early'. + Some components needs to be initialized as early as possible, + because the rest of the server initialization depends on them. + Options that needs to be parsed early includes: + - the performance schema, when compiled in, + - options related to the help, + - options related to the bootstrap + The performance schema needs to be initialized as early as possible, + before to-be-instrumented objects of the server are initialized. */ -static int -show_ssl_get_server_not_after(THD *thd, SHOW_VAR *var, char *buff) -{ - var->type= SHOW_CHAR; - if(thd->vio_ok() && thd->net.vio->ssl_arg) - { - SSL *ssl= (SSL*) thd->net.vio->ssl_arg; - X509 *cert= SSL_get_certificate(ssl); - ASN1_TIME *not_after= X509_get_notAfter(cert); - - var->value= my_asn1_time_to_string(not_after, buff, - SHOW_VAR_FUNC_BUFF_SIZE); - if (!var->value) - return 1; - } - else - var->value= empty_c_string; - return 0; -} - -#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ - -static int show_default_keycache(THD *thd, SHOW_VAR *var, char *buff) +int handle_early_options() { - struct st_data { - KEY_CACHE_STATISTICS stats; - SHOW_VAR var[8]; - } *data; - SHOW_VAR *v; - - data=(st_data *)buff; - v= data->var; - - var->type= SHOW_ARRAY; - var->value= (char*)v; + int ho_error; + DYNAMIC_ARRAY all_early_options; - get_key_cache_statistics(dflt_key_cache, 0, &data->stats); + my_getopt_register_get_addr(NULL); + /* Skip unknown options so that they may be processed later */ + my_getopt_skip_unknown= TRUE; -#define set_one_keycache_var(X,Y) \ - v->name= X; \ - v->type= SHOW_LONGLONG; \ - v->value= (char*)&data->stats.Y; \ - v++; + /* prepare all_early_options array */ + my_init_dynamic_array(&all_early_options, sizeof(my_option), 100, 25, MYF(0)); + add_many_options(&all_early_options, pfs_early_options, + array_elements(pfs_early_options)); + sys_var_add_options(&all_early_options, sys_var::PARSE_EARLY); + add_terminator(&all_early_options); - set_one_keycache_var("blocks_not_flushed", blocks_changed); - set_one_keycache_var("blocks_unused", blocks_unused); - set_one_keycache_var("blocks_used", blocks_used); - set_one_keycache_var("blocks_warm", blocks_warm); - set_one_keycache_var("read_requests", read_requests); - set_one_keycache_var("reads", reads); - set_one_keycache_var("write_requests", write_requests); - set_one_keycache_var("writes", writes); + ho_error= handle_options(&remaining_argc, &remaining_argv, + (my_option*)(all_early_options.buffer), + mysqld_get_one_option); + if (ho_error == 0) + { + /* Add back the program name handle_options removes */ + remaining_argc++; + remaining_argv--; + } - v->name= 0; + delete_dynamic(&all_early_options); - DBUG_ASSERT((char*)(v+1) <= buff + SHOW_VAR_FUNC_BUFF_SIZE); + return ho_error; +} -#undef set_one_keycache_var - return 0; -} +/** + System variables are automatically command-line options (few + exceptions are documented in sys_var.h), so don't need + to be listed here. +*/ -#ifdef HAVE_POOL_OF_THREADS -int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff) +struct my_option my_long_options[]= { - var->type= SHOW_INT; - var->value= buff; - *(int *)buff= tp_get_idle_thread_count(); - return 0; -} + {"help", '?', "Display this help and exit.", + &opt_help, &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, + {"allow-suspicious-udfs", 0, + "Allows use of UDFs consisting of only one symbol xxx() " + "without corresponding xxx_init() or xxx_deinit(). That also means " + "that one can load any function from any library, for example exit() " + "from libc.so", + &opt_allow_suspicious_udfs, &opt_allow_suspicious_udfs, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode " + "will also set transaction isolation level 'serializable'.", 0, 0, 0, + GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + /* + Because Sys_var_bit does not support command-line options, we need to + explicitely add one for --autocommit + */ + {"autocommit", 0, "Set default value for autocommit (0 or 1)", + &opt_autocommit, &opt_autocommit, 0, + GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, NULL}, + {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.", + &my_bind_addr_str, &my_bind_addr_str, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"binlog-do-db", OPT_BINLOG_DO_DB, + "Tells the master it should log updates for the specified database, " + "and exclude all others not explicitly mentioned.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, + "Tells the master that updates to the given database should not be logged to the binary log.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"binlog-row-event-max-size", 0, + "The maximum size of a row-based binary log event in bytes. Rows will be " + "grouped into events smaller than this size if possible. " + "The value has to be a multiple of 256.", + &opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size, + 0, GET_ULONG, REQUIRED_ARG, + /* def_value */ 1024, /* min_value */ 256, /* max_value */ ULONG_MAX, + /* sub_size */ 0, /* block_size */ 256, + /* app_type */ 0 + }, +#ifndef DISABLE_GRANT_OPTIONS + {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0, + GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"character-set-client-handshake", 0, + "Don't ignore client side character set value sent during handshake.", + &opt_character_set_client_handshake, + &opt_character_set_client_handshake, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"character-set-filesystem", 0, + "Set the filesystem character set.", + &character_set_filesystem_name, + &character_set_filesystem_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + {"character-set-server", 'C', "Set the default character set.", + &default_character_set_name, &default_character_set_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + {"chroot", 'r', "Chroot mysqld daemon during startup.", + &mysqld_chroot, &mysqld_chroot, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"collation-server", 0, "Set the default collation.", + &default_collation_name, &default_collation_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + {"console", OPT_CONSOLE, "Write error output on screen; don't remove the console window on windows.", + &opt_console, &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, + {"core-file", OPT_WANT_CORE, "Write core on errors.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + /* default-storage-engine should have "MyISAM" as def_value. Instead + of initializing it here it is done in init_common_variables() due + to a compiler bug in Sun Studio compiler. */ +#ifdef DBUG_OFF + {"debug", '#', "Built in DBUG debugger. Disabled in this build.", + ¤t_dbug_option, ¤t_dbug_option, 0, GET_STR, OPT_ARG, + 0, 0, 0, 0, 0, 0}, #endif - -/* - Variables shown by SHOW STATUS in alphabetical order -*/ - -SHOW_VAR status_vars[]= { - {"Aborted_clients", (char*) &aborted_threads, SHOW_LONG}, - {"Aborted_connects", (char*) &aborted_connects, SHOW_LONG}, - {"Access_denied_errors", (char*) offsetof(STATUS_VAR, access_denied_errors), SHOW_LONG_STATUS}, - {"Binlog_bytes_written", (char*) offsetof(STATUS_VAR, binlog_bytes_written), SHOW_LONGLONG_STATUS}, - {"Binlog_cache_disk_use", (char*) &binlog_cache_disk_use, SHOW_LONG}, - {"Binlog_cache_use", (char*) &binlog_cache_use, SHOW_LONG}, - {"Binlog_stmt_cache_disk_use",(char*) &binlog_stmt_cache_disk_use, SHOW_LONG}, - {"Binlog_stmt_cache_use", (char*) &binlog_stmt_cache_use, SHOW_LONG}, - {"Busy_time", (char*) offsetof(STATUS_VAR, busy_time), SHOW_DOUBLE_STATUS}, - {"Bytes_received", (char*) offsetof(STATUS_VAR, bytes_received), SHOW_LONGLONG_STATUS}, - {"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONGLONG_STATUS}, - {"Com", (char*) com_status_vars, SHOW_ARRAY}, - {"Compression", (char*) &show_net_compression, SHOW_SIMPLE_FUNC}, - {"Connections", (char*) &thread_id, SHOW_LONG_NOFLUSH}, - {"Connection_errors_accept", (char*) &connection_errors_accept, SHOW_LONG}, - {"Connection_errors_internal", (char*) &connection_errors_internal, SHOW_LONG}, - {"Connection_errors_max_connections", (char*) &connection_errors_max_connection, SHOW_LONG}, - {"Connection_errors_peer_address", (char*) &connection_errors_peer_addr, SHOW_LONG}, - {"Connection_errors_select", (char*) &connection_errors_select, SHOW_LONG}, - {"Connection_errors_tcpwrap", (char*) &connection_errors_tcpwrap, SHOW_LONG}, - {"Cpu_time", (char*) offsetof(STATUS_VAR, cpu_time), SHOW_DOUBLE_STATUS}, - {"Created_tmp_disk_tables", (char*) offsetof(STATUS_VAR, created_tmp_disk_tables_), SHOW_LONG_STATUS}, - {"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG}, - {"Created_tmp_tables", (char*) offsetof(STATUS_VAR, created_tmp_tables_), SHOW_LONG_STATUS}, - {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, - {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_NOFLUSH}, - {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, - {"Empty_queries", (char*) offsetof(STATUS_VAR, empty_queries), SHOW_LONG_STATUS}, - {"Executed_events", (char*) &executed_events, SHOW_LONG_NOFLUSH }, - {"Executed_triggers", (char*) offsetof(STATUS_VAR, executed_triggers), SHOW_LONG_STATUS}, - {"Feature_dynamic_columns", (char*) offsetof(STATUS_VAR, feature_dynamic_columns), SHOW_LONG_STATUS}, - {"Feature_fulltext", (char*) offsetof(STATUS_VAR, feature_fulltext), SHOW_LONG_STATUS}, - {"Feature_gis", (char*) offsetof(STATUS_VAR, feature_gis), SHOW_LONG_STATUS}, - {"Feature_locale", (char*) offsetof(STATUS_VAR, feature_locale), SHOW_LONG_STATUS}, - {"Feature_subquery", (char*) offsetof(STATUS_VAR, feature_subquery), SHOW_LONG_STATUS}, - {"Feature_timezone", (char*) offsetof(STATUS_VAR, feature_timezone), SHOW_LONG_STATUS}, - {"Feature_trigger", (char*) offsetof(STATUS_VAR, feature_trigger), SHOW_LONG_STATUS}, - {"Feature_xml", (char*) offsetof(STATUS_VAR, feature_xml), SHOW_LONG_STATUS}, - {"Flush_commands", (char*) &show_flush_commands, SHOW_SIMPLE_FUNC}, - {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, - {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, - {"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS}, - {"Handler_external_lock", (char*) offsetof(STATUS_VAR, ha_external_lock_count), SHOW_LONGLONG_STATUS}, - {"Handler_icp_attempts", (char*) offsetof(STATUS_VAR, ha_icp_attempts), SHOW_LONG_STATUS}, - {"Handler_icp_match", (char*) offsetof(STATUS_VAR, ha_icp_match), SHOW_LONG_STATUS}, - {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_mrr_init_count), SHOW_LONG_STATUS}, - {"Handler_mrr_key_refills", (char*) offsetof(STATUS_VAR, ha_mrr_key_refills_count), SHOW_LONG_STATUS}, - {"Handler_mrr_rowid_refills",(char*) offsetof(STATUS_VAR, ha_mrr_rowid_refills_count), SHOW_LONG_STATUS}, - {"Handler_prepare", (char*) offsetof(STATUS_VAR, ha_prepare_count), SHOW_LONG_STATUS}, - {"Handler_read_first", (char*) offsetof(STATUS_VAR, ha_read_first_count), SHOW_LONG_STATUS}, - {"Handler_read_key", (char*) offsetof(STATUS_VAR, ha_read_key_count), SHOW_LONG_STATUS}, - {"Handler_read_last", (char*) offsetof(STATUS_VAR, ha_read_last_count), SHOW_LONG_STATUS}, - {"Handler_read_next", (char*) offsetof(STATUS_VAR, ha_read_next_count), SHOW_LONG_STATUS}, - {"Handler_read_prev", (char*) offsetof(STATUS_VAR, ha_read_prev_count), SHOW_LONG_STATUS}, - {"Handler_read_rnd", (char*) offsetof(STATUS_VAR, ha_read_rnd_count), SHOW_LONG_STATUS}, - {"Handler_read_rnd_deleted", (char*) offsetof(STATUS_VAR, ha_read_rnd_deleted_count), SHOW_LONG_STATUS}, - {"Handler_read_rnd_next", (char*) offsetof(STATUS_VAR, ha_read_rnd_next_count), SHOW_LONG_STATUS}, - {"Handler_rollback", (char*) offsetof(STATUS_VAR, ha_rollback_count), SHOW_LONG_STATUS}, - {"Handler_savepoint", (char*) offsetof(STATUS_VAR, ha_savepoint_count), SHOW_LONG_STATUS}, - {"Handler_savepoint_rollback",(char*) offsetof(STATUS_VAR, ha_savepoint_rollback_count), SHOW_LONG_STATUS}, - {"Handler_tmp_update", (char*) offsetof(STATUS_VAR, ha_tmp_update_count), SHOW_LONG_STATUS}, - {"Handler_tmp_write", (char*) offsetof(STATUS_VAR, ha_tmp_write_count), SHOW_LONG_STATUS}, - {"Handler_update", (char*) offsetof(STATUS_VAR, ha_update_count), SHOW_LONG_STATUS}, - {"Handler_write", (char*) offsetof(STATUS_VAR, ha_write_count), SHOW_LONG_STATUS}, - {"Key", (char*) &show_default_keycache, SHOW_FUNC}, - {"Last_query_cost", (char*) offsetof(STATUS_VAR, last_query_cost), SHOW_DOUBLE_STATUS}, - {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, - {"Memory_used", (char*) offsetof(STATUS_VAR, memory_used), SHOW_LONGLONG_STATUS}, - {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_NOFLUSH}, - {"Open_files", (char*) &my_file_opened, SHOW_LONG_NOFLUSH}, - {"Open_streams", (char*) &my_stream_opened, SHOW_LONG_NOFLUSH}, - {"Open_table_definitions", (char*) &show_table_definitions, SHOW_SIMPLE_FUNC}, - {"Open_tables", (char*) &show_open_tables, SHOW_SIMPLE_FUNC}, - {"Opened_files", (char*) &my_file_total_opened, SHOW_LONG_NOFLUSH}, - {"Opened_plugin_libraries", (char*) &dlopen_count, SHOW_LONG}, - {"Opened_table_definitions", (char*) offsetof(STATUS_VAR, opened_shares), SHOW_LONG_STATUS}, - {"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS}, - {"Opened_views", (char*) offsetof(STATUS_VAR, opened_views), SHOW_LONG_STATUS}, - {"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_SIMPLE_FUNC}, - {"Rows_sent", (char*) offsetof(STATUS_VAR, rows_sent), SHOW_LONGLONG_STATUS}, - {"Rows_read", (char*) offsetof(STATUS_VAR, rows_read), SHOW_LONGLONG_STATUS}, - {"Rows_tmp_read", (char*) offsetof(STATUS_VAR, rows_tmp_read), SHOW_LONGLONG_STATUS}, -#ifdef HAVE_QUERY_CACHE - {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_NOFLUSH}, - {"Qcache_free_memory", (char*) &query_cache.free_memory, SHOW_LONG_NOFLUSH}, - {"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG}, - {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG}, - {"Qcache_lowmem_prunes", (char*) &query_cache.lowmem_prunes, SHOW_LONG}, - {"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG}, - {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_NOFLUSH}, - {"Qcache_total_blocks", (char*) &query_cache.total_blocks, SHOW_LONG_NOFLUSH}, -#endif /*HAVE_QUERY_CACHE*/ - {"Queries", (char*) &show_queries, SHOW_SIMPLE_FUNC}, - {"Questions", (char*) offsetof(STATUS_VAR, questions), SHOW_LONG_STATUS}, #ifdef HAVE_REPLICATION - {"Rpl_status", (char*) &show_rpl_status, SHOW_SIMPLE_FUNC}, + {"debug-abort-slave-event-count", 0, + "Option used by mysql-test for debugging and testing of replication.", + &abort_slave_event_count, &abort_slave_event_count, + 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif /* HAVE_REPLICATION */ +#ifndef DBUG_OFF + {"debug-assert-on-error", 0, + "Do an assert in various functions if we get a fatal error", + &my_assert_on_error, &my_assert_on_error, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-assert-if-crashed-table", 0, + "Do an assert in handler::print_error() if we get a crashed table", + &debug_assert_if_crashed_table, &debug_assert_if_crashed_table, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif +#ifdef HAVE_REPLICATION + {"debug-disconnect-slave-event-count", 0, + "Option used by mysql-test for debugging and testing of replication.", + &disconnect_slave_event_count, &disconnect_slave_event_count, + 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif /* HAVE_REPLICATION */ + {"debug-exit-info", 'T', "Used for debugging. Use at your own risk.", + 0, 0, 0, GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-gdb", 0, + "Set up signals usable for debugging.", + &opt_debugging, &opt_debugging, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_REPLICATION + {"debug-max-binlog-dump-events", 0, + "Option used by mysql-test for debugging and testing of replication.", + &max_binlog_dump_events, &max_binlog_dump_events, 0, + GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif /* HAVE_REPLICATION */ +#ifdef SAFE_MUTEX + {"debug-mutex-deadlock-detector", 0, + "Enable checking of wrong mutex usage.", + &safe_mutex_deadlock_detector, + &safe_mutex_deadlock_detector, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, +#endif + {"debug-no-sync", 0, + "Disables system sync calls. Only for running tests or debugging!", + &my_disable_sync, &my_disable_sync, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_REPLICATION + {"debug-sporadic-binlog-dump-fail", 0, + "Option used by mysql-test for debugging and testing of replication.", + &opt_sporadic_binlog_dump_fail, + &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + 0}, +#endif /* HAVE_REPLICATION */ + {"default-storage-engine", 0, "The default storage engine for new tables", + &default_storage_engine, 0, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0 }, + {"default-time-zone", 0, "Set the default time zone.", + &default_tz_name, &default_tz_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, +#if defined(ENABLED_DEBUG_SYNC) + {"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT, + "Enable the debug sync facility " + "and optionally specify a default wait timeout in seconds. " + "A zero value keeps the facility disabled.", + &opt_debug_sync_timeout, 0, + 0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0}, +#endif /* defined(ENABLED_DEBUG_SYNC) */ +#ifdef HAVE_OPENSSL + {"des-key-file", 0, + "Load keys for des_encrypt() and des_encrypt from given file.", + &des_key_file, &des_key_file, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, +#endif /* HAVE_OPENSSL */ +#ifdef HAVE_STACKTRACE + {"stack-trace", 0 , "Print a symbolic stack trace on failure", + &opt_stack_trace, &opt_stack_trace, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, +#endif /* HAVE_STACKTRACE */ + {"external-locking", 0, "Use system (external) locking (disabled by " + "default). With this option enabled you can run myisamchk to test " + "(not repair) tables while the MySQL server is running. Disable with " + "--skip-external-locking.", &opt_external_locking, &opt_external_locking, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + /* We must always support the next option to make scripts like mysqltest + easier to do */ + {"gdb", 0, + "Set up signals usable for debugging. Deprecated, use --debug-gdb instead.", + &opt_debugging, &opt_debugging, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_LARGE_PAGE_OPTION + {"super-large-pages", 0, "Enable support for super large pages.", + &opt_super_large_pages, &opt_super_large_pages, 0, + GET_BOOL, OPT_ARG, 0, 0, 1, 0, 1, 0}, +#endif + {"language", 'L', + "Client error messages in given language. May be given as a full path. " + "Deprecated. Use --lc-messages-dir instead.", + 0, 0, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"lc-messages", 0, + "Set the language used for the error messages.", + &lc_messages, &lc_messages, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0 }, + {"lc-time-names", 0, + "Set the language used for the month names and the days of the week.", + &lc_time_names_name, &lc_time_names_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + {"log-basename", OPT_LOG_BASENAME, + "Basename for all log files and the .pid file. This sets all log file " + "names at once (in 'datadir') and is normally the only option you need " + "for specifying log files. Sets names for --log-bin, --log-bin-index, " + "--relay-log, --relay-log-index, --general-log-file, " + "--log-slow-query-log-file, --log-error-file, and --pid-file", + &opt_log_basename, &opt_log_basename, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"log-bin", OPT_BIN_LOG, + "Log update queries in binary format. Optional argument should be name for " + "binary log. If not given " + "'datadir'/'log-basename'-bin or 'datadir'/mysql-bin will be used (the later if " + "--log-basename is not specified). We strongly recommend to use either " + "--log-basename or specify a filename to ensure that replication doesn't " + "stop if the real hostname of the computer changes.", + &opt_bin_logname, &opt_bin_logname, 0, GET_STR, + OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"log-bin-index", 0, + "File that holds the names for last binary log files.", + &opt_binlog_index_name, &opt_binlog_index_name, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"log-isam", OPT_ISAM_LOG, "Log all MyISAM changes to file.", + &myisam_log_filename, &myisam_log_filename, 0, GET_STR, + OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"log-short-format", 0, + "Don't log extra information to update and slow-query logs.", + &opt_short_log_format, &opt_short_log_format, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"log-slow-admin-statements", 0, + "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to " + "the slow log if it is open.", &opt_log_slow_admin_statements, + &opt_log_slow_admin_statements, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"log-slow-slave-statements", 0, + "Log slow statements executed by slave thread to the slow log if it is open.", + &opt_log_slow_slave_statements, &opt_log_slow_slave_statements, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"log-tc", 0, + "Path to transaction coordinator log (used for transactions that affect " + "more than one storage engine, when binary log is disabled).", + &opt_tc_log_file, &opt_tc_log_file, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_MMAP + {"log-tc-size", 0, "Size of transaction coordinator log.", + &opt_tc_log_size, &opt_tc_log_size, 0, GET_ULONG, + REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, (ulonglong) ULONG_MAX, 0, + TC_LOG_PAGE_SIZE, 0}, #endif - {"Select_full_join", (char*) offsetof(STATUS_VAR, select_full_join_count_), SHOW_LONG_STATUS}, - {"Select_full_range_join", (char*) offsetof(STATUS_VAR, select_full_range_join_count_), SHOW_LONG_STATUS}, - {"Select_range", (char*) offsetof(STATUS_VAR, select_range_count_), SHOW_LONG_STATUS}, - {"Select_range_check", (char*) offsetof(STATUS_VAR, select_range_check_count_), SHOW_LONG_STATUS}, - {"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count_), SHOW_LONG_STATUS}, - {"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG}, + {"master-info-file", 0, + "The location and name of the file that remembers the master and where " + "the I/O replication thread is in the master's binlogs. Defaults to " + "master.info", + &master_info_file, &master_info_file, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"master-retry-count", 0, + "The number of tries the slave will make to connect to the master before giving up.", + &master_retry_count, &master_retry_count, 0, GET_ULONG, + REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0}, #ifdef HAVE_REPLICATION - {"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_SIMPLE_FUNC}, - {"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_SIMPLE_FUNC}, - {"Slave_retried_transactions",(char*)&slave_retried_transactions, SHOW_LONG}, - {"Slave_running", (char*) &show_slave_running, SHOW_SIMPLE_FUNC}, + {"init-rpl-role", 0, "Set the replication role.", + &rpl_status, &rpl_status, &rpl_role_typelib, + GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif /* HAVE_REPLICATION */ + {"memlock", 0, "Lock mysqld in memory.", &locked_in_memory, + &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"old-style-user-limits", 0, + "Enable old-style user limits (before 5.0.3, user resources were counted " + "per each user+host vs. per account).", + &opt_old_style_user_limits, &opt_old_style_user_limits, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"port-open-timeout", 0, + "Maximum time in seconds to wait for the port to become free. " + "(Default: No wait).", &mysqld_port_timeout, &mysqld_port_timeout, 0, + GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"replicate-do-db", OPT_REPLICATE_DO_DB, + "Tells the slave thread to restrict replication to the specified database. " + "To specify more than one database, use the directive multiple times, " + "once for each database. Note that this will only work if you do not use " + "cross-database queries such as UPDATE some_db.some_table SET foo='bar' " + "while having selected a different or no database. If you need cross " + "database updates to work, make sure you have 3.23.28 or later, and use " + "replicate-wild-do-table=db_name.%.", + 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"replicate-do-table", OPT_REPLICATE_DO_TABLE, + "Tells the slave thread to restrict replication to the specified table. " + "To specify more than one table, use the directive multiple times, once " + "for each table. This will work for cross-database updates, in contrast " + "to replicate-do-db.", 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"replicate-ignore-db", OPT_REPLICATE_IGNORE_DB, + "Tells the slave thread to not replicate to the specified database. To " + "specify more than one database to ignore, use the directive multiple " + "times, once for each database. This option will not work if you use " + "cross database updates. If you need cross database updates to work, " + "make sure you have 3.23.28 or later, and use replicate-wild-ignore-" + "table=db_name.%. ", 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"replicate-ignore-table", OPT_REPLICATE_IGNORE_TABLE, + "Tells the slave thread to not replicate to the specified table. To specify " + "more than one table to ignore, use the directive multiple times, once for " + "each table. This will work for cross-database updates, in contrast to " + "replicate-ignore-db.", 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"replicate-rewrite-db", OPT_REPLICATE_REWRITE_DB, + "Updates to a database with a different name than the original. Example: " + "replicate-rewrite-db=master_db_name->slave_db_name.", + 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_REPLICATION + {"replicate-same-server-id", 0, + "In replication, if set to 1, do not skip events having our server id. " + "Default value is 0 (to break infinite loops in circular replication). " + "Can't be set to 1 if --log-slave-updates is used.", + &replicate_same_server_id, &replicate_same_server_id, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG}, - {"Slow_queries", (char*) offsetof(STATUS_VAR, long_query_count), SHOW_LONG_STATUS}, - {"Sort_merge_passes", (char*) offsetof(STATUS_VAR, filesort_merge_passes_), SHOW_LONG_STATUS}, - {"Sort_range", (char*) offsetof(STATUS_VAR, filesort_range_count_), SHOW_LONG_STATUS}, - {"Sort_rows", (char*) offsetof(STATUS_VAR, filesort_rows_), SHOW_LONG_STATUS}, - {"Sort_scan", (char*) offsetof(STATUS_VAR, filesort_scan_count_), SHOW_LONG_STATUS}, -#ifdef HAVE_OPENSSL -#ifndef EMBEDDED_LIBRARY - {"Ssl_accept_renegotiates", (char*) &show_ssl_ctx_sess_accept_renegotiate, SHOW_SIMPLE_FUNC}, - {"Ssl_accepts", (char*) &show_ssl_ctx_sess_accept, SHOW_SIMPLE_FUNC}, - {"Ssl_callback_cache_hits", (char*) &show_ssl_ctx_sess_cb_hits, SHOW_SIMPLE_FUNC}, - {"Ssl_cipher", (char*) &show_ssl_get_cipher, SHOW_SIMPLE_FUNC}, - {"Ssl_cipher_list", (char*) &show_ssl_get_cipher_list, SHOW_SIMPLE_FUNC}, - {"Ssl_client_connects", (char*) &show_ssl_ctx_sess_connect, SHOW_SIMPLE_FUNC}, - {"Ssl_connect_renegotiates", (char*) &show_ssl_ctx_sess_connect_renegotiate, SHOW_SIMPLE_FUNC}, - {"Ssl_ctx_verify_depth", (char*) &show_ssl_ctx_get_verify_depth, SHOW_SIMPLE_FUNC}, - {"Ssl_ctx_verify_mode", (char*) &show_ssl_ctx_get_verify_mode, SHOW_SIMPLE_FUNC}, - {"Ssl_default_timeout", (char*) &show_ssl_get_default_timeout, SHOW_SIMPLE_FUNC}, - {"Ssl_finished_accepts", (char*) &show_ssl_ctx_sess_accept_good, SHOW_SIMPLE_FUNC}, - {"Ssl_finished_connects", (char*) &show_ssl_ctx_sess_connect_good, SHOW_SIMPLE_FUNC}, - {"Ssl_server_not_after", (char*) &show_ssl_get_server_not_after, SHOW_SIMPLE_FUNC}, - {"Ssl_server_not_before", (char*) &show_ssl_get_server_not_before, SHOW_SIMPLE_FUNC}, - {"Ssl_session_cache_hits", (char*) &show_ssl_ctx_sess_hits, SHOW_SIMPLE_FUNC}, - {"Ssl_session_cache_misses", (char*) &show_ssl_ctx_sess_misses, SHOW_SIMPLE_FUNC}, - {"Ssl_session_cache_mode", (char*) &show_ssl_ctx_get_session_cache_mode, SHOW_SIMPLE_FUNC}, - {"Ssl_session_cache_overflows", (char*) &show_ssl_ctx_sess_cache_full, SHOW_SIMPLE_FUNC}, - {"Ssl_session_cache_size", (char*) &show_ssl_ctx_sess_get_cache_size, SHOW_SIMPLE_FUNC}, - {"Ssl_session_cache_timeouts", (char*) &show_ssl_ctx_sess_timeouts, SHOW_SIMPLE_FUNC}, - {"Ssl_sessions_reused", (char*) &show_ssl_session_reused, SHOW_SIMPLE_FUNC}, - {"Ssl_used_session_cache_entries",(char*) &show_ssl_ctx_sess_number, SHOW_SIMPLE_FUNC}, - {"Ssl_verify_depth", (char*) &show_ssl_get_verify_depth, SHOW_SIMPLE_FUNC}, - {"Ssl_verify_mode", (char*) &show_ssl_get_verify_mode, SHOW_SIMPLE_FUNC}, - {"Ssl_version", (char*) &show_ssl_get_version, SHOW_SIMPLE_FUNC}, + {"replicate-wild-do-table", OPT_REPLICATE_WILD_DO_TABLE, + "Tells the slave thread to restrict replication to the tables that match " + "the specified wildcard pattern. To specify more than one table, use the " + "directive multiple times, once for each table. This will work for cross-" + "database updates. Example: replicate-wild-do-table=foo%.bar% will " + "replicate only updates to tables in all databases that start with foo " + "and whose table names start with bar.", + 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"replicate-wild-ignore-table", OPT_REPLICATE_WILD_IGNORE_TABLE, + "Tells the slave thread to not replicate to the tables that match the " + "given wildcard pattern. To specify more than one table to ignore, use " + "the directive multiple times, once for each table. This will work for " + "cross-database updates. Example: replicate-wild-ignore-table=foo%.bar% " + "will not do updates to tables in databases that start with foo and whose " + "table names start with bar.", + 0, 0, 0, GET_STR | GET_ASK_ADDR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing). Deprecated.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"safe-user-create", 0, + "Don't allow new user creation by the user who has no write privileges to the mysql.user table.", + &opt_safe_user_create, &opt_safe_user_create, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {"show-slave-auth-info", 0, + "Show user and password in SHOW SLAVE HOSTS on this master.", + &opt_show_slave_auth_info, &opt_show_slave_auth_info, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"skip-bdb", OPT_DEPRECATED_OPTION, + "Deprecated option; Exist only for compatiblity with old my.cnf files", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DISABLE_GRANT_OPTIONS + {"skip-grant-tables", 0, + "Start without grant tables. This gives all users FULL ACCESS to all tables.", + &opt_noacl, &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + 0}, #endif -#endif /* HAVE_OPENSSL */ - {"Syncs", (char*) &my_sync_count, SHOW_LONG_NOFLUSH}, - /* - Expression cache used only for caching subqueries now, so its statistic - variables we call subquery_cache*. - */ - {"Subquery_cache_hit", (char*) &subquery_cache_hit, SHOW_LONG}, - {"Subquery_cache_miss", (char*) &subquery_cache_miss, SHOW_LONG}, - {"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG}, - {"Table_locks_waited", (char*) &locks_waited, SHOW_LONG}, -#ifdef HAVE_MMAP - {"Tc_log_max_pages_used", (char*) &tc_log_max_pages_used, SHOW_LONG}, - {"Tc_log_page_size", (char*) &tc_log_page_size, SHOW_LONG_NOFLUSH}, - {"Tc_log_page_waits", (char*) &tc_log_page_waits, SHOW_LONG}, + {"skip-host-cache", OPT_SKIP_HOST_CACHE, "Don't cache host names.", 0, 0, 0, + GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"skip-slave-start", 0, + "If set, slave is not autostarted.", &opt_skip_slave_start, + &opt_skip_slave_start, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) + {"slow-start-timeout", 0, + "Maximum number of milliseconds that the service control manager should wait " + "before trying to kill the windows service during startup" + "(Default: 15000).", &slow_start_timeout, &slow_start_timeout, 0, + GET_ULONG, REQUIRED_ARG, 15000, 0, 0, 0, 0, 0}, #endif -#ifdef HAVE_POOL_OF_THREADS - {"Threadpool_idle_threads", (char *) &show_threadpool_idle_threads, SHOW_SIMPLE_FUNC}, - {"Threadpool_threads", (char *) &tp_stats.num_worker_threads, SHOW_INT}, +#ifdef HAVE_OPENSSL + {"ssl", 0, + "Enable SSL for connection (automatically enabled if an ssl option is used).", + &opt_use_ssl, &opt_use_ssl, 0, GET_BOOL, OPT_ARG, 0, 0, 0, + 0, 0, 0}, #endif - {"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_NOFLUSH}, - {"Threads_connected", (char*) &connection_count, SHOW_INT}, - {"Threads_created", (char*) &thread_created, SHOW_LONG_NOFLUSH}, - {"Threads_running", (char*) &thread_running, SHOW_INT}, - {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, -#ifdef ENABLED_PROFILING - {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC}, +#ifdef __WIN__ + {"standalone", 0, + "Dummy option to start as a standalone program (NT).", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, #endif -#ifdef WITH_WSREP - {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL}, - {"wsrep_ready", (char*) &wsrep_ready, SHOW_BOOL}, - {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, - {"wsrep_cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, - {"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, - {"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG}, - {"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG}, - {"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, - {"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, - {"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, - {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC}, + {"symbolic-links", 's', "Enable symbolic link support.", + &my_use_symdir, &my_use_symdir, 0, GET_BOOL, NO_ARG, + /* + The system call realpath() produces warnings under valgrind and + purify. These are not suppressed: instead we disable symlinks + option if compiled with valgrind support. + Also disable by default on Windows, due to high overhead for checking .sym + files. + */ + IF_VALGRIND(0,IF_WIN(0,1)), 0, 0, 0, 0, 0}, + {"sysdate-is-now", 0, + "Non-default option to alias SYSDATE() to NOW() to make it safe-replicable. " + "Since 5.0, SYSDATE() returns a `dynamic' value different for different " + "invocations, even within the same statement.", + &global_system_variables.sysdate_is_now, + 0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, + {"tc-heuristic-recover", 0, + "Decision to use in heuristic recover process. Possible values are COMMIT " + "or ROLLBACK.", &tc_heuristic_recover, &tc_heuristic_recover, + &tc_heuristic_recover_typelib, GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"temp-pool", 0, +#if (ENABLE_TEMP_POOL) + "Using this option will cause most temporary files created to use a small " + "set of names, rather than a unique name for each new file.", +#else + "This option is ignored on this OS.", #endif - {NullS, NullS, SHOW_LONG} + &use_temp_pool, &use_temp_pool, 0, GET_BOOL, NO_ARG, 1, + 0, 0, 0, 0, 0}, + {"transaction-isolation", 0, + "Default transaction isolation level.", + &global_system_variables.tx_isolation, + &global_system_variables.tx_isolation, &tx_isolation_typelib, + GET_ENUM, REQUIRED_ARG, ISO_REPEATABLE_READ, 0, 0, 0, 0, 0}, + {"transaction-read-only", 0, + "Default transaction access mode. " + "True if transactions are read-only.", + &global_system_variables.tx_read_only, + &global_system_variables.tx_read_only, 0, + GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"verbose", 'v', "Used with --help option for detailed help.", + &opt_verbose, &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-load", OPT_PLUGIN_LOAD, + "Semicolon-separated list of plugins to load, where each plugin is " + "specified as ether a plugin_name=library_file pair or only a library_file. " + "If the latter case, all plugins from a given library_file will be loaded.", + 0, 0, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-load-add", OPT_PLUGIN_LOAD_ADD, + "Optional semicolon-separated list of plugins to load. This option adds " + "to the list speficied by --plugin-load in an incremental way. " + "It can be specified many times, adding more plugins every time.", + 0, 0, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"table_cache", 0, "Deprecated; use --table-open-cache instead.", + &tc_size, &tc_size, 0, GET_ULONG, + REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0} }; -static bool add_terminator(DYNAMIC_ARRAY *options) +static int show_queries(THD *thd, SHOW_VAR *var, char *buff) { - my_option empty_element= {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}; - return insert_dynamic(options, (uchar *)&empty_element); + var->type= SHOW_LONGLONG; + var->value= (char *)&thd->query_id; + return 0; } -static bool add_many_options(DYNAMIC_ARRAY *options, my_option *list, - size_t elements) + +static int show_net_compression(THD *thd, SHOW_VAR *var, char *buff) { - for (my_option *opt= list; opt < list + elements; opt++) - if (insert_dynamic(options, opt)) - return 1; + var->type= SHOW_MY_BOOL; + var->value= (char *)&thd->net.compress; return 0; } -#ifndef EMBEDDED_LIBRARY -static void print_version(void) +static int show_starttime(THD *thd, SHOW_VAR *var, char *buff) { - set_server_version(); + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (long) (thd->query_start() - server_start_time); + return 0; +} - printf("%s Ver %s for %s on %s (%s)\n",my_progname, - server_version,SYSTEM_TYPE,MACHINE_TYPE, MYSQL_COMPILATION_COMMENT); +#ifdef ENABLED_PROFILING +static int show_flushstatustime(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (long) (thd->query_start() - flush_status_time); + return 0; } +#endif -/** Compares two options' names, treats - and _ the same */ -static int option_cmp(my_option *a, my_option *b) +#ifdef HAVE_REPLICATION +static int show_rpl_status(THD *thd, SHOW_VAR *var, char *buff) { - const char *sa= a->name; - const char *sb= b->name; - for (; *sa || *sb; sa++, sb++) + var->type= SHOW_CHAR; + var->value= const_cast(rpl_status_type[(int)rpl_status]); + return 0; +} + +static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff) +{ + Master_info *mi= NULL; + bool tmp; + LINT_INIT(tmp); + + var->type= SHOW_MY_BOOL; + var->value= buff; + mysql_mutex_unlock(&LOCK_status); + mysql_mutex_lock(&LOCK_active_mi); + if (master_info_index) { - if (*sa < *sb) - { - if (*sa == '-' && *sb == '_') - continue; - else - return -1; - } - if (*sa > *sb) - { - if (*sa == '_' && *sb == '-') - continue; - else - return 1; - } + mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + Sql_condition::WARN_LEVEL_NOTE); + if (mi) + tmp= (my_bool) (mi->slave_running == MYSQL_SLAVE_RUN_CONNECT && + mi->rli.slave_running); } - DBUG_ASSERT(a->name == b->name); + mysql_mutex_unlock(&LOCK_active_mi); + mysql_mutex_lock(&LOCK_status); + if (mi) + *((my_bool *)buff)= tmp; + else + var->type= SHOW_UNDEF; return 0; } -static void print_help() + +static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff) { - MEM_ROOT mem_root; - init_alloc_root(&mem_root, 4096, 4096, MYF(0)); + Master_info *mi= NULL; + longlong tmp; + LINT_INIT(tmp); - pop_dynamic(&all_options); - add_many_options(&all_options, pfs_early_options, - array_elements(pfs_early_options)); - sys_var_add_options(&all_options, sys_var::PARSE_EARLY); - add_plugin_options(&all_options, &mem_root); - sort_dynamic(&all_options, (qsort_cmp) option_cmp); - add_terminator(&all_options); + var->type= SHOW_LONGLONG; + var->value= buff; + mysql_mutex_unlock(&LOCK_status); + mysql_mutex_lock(&LOCK_active_mi); + if (master_info_index) + { + mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + Sql_condition::WARN_LEVEL_NOTE); + if (mi) + tmp= mi->received_heartbeats; + } + mysql_mutex_unlock(&LOCK_active_mi); + mysql_mutex_lock(&LOCK_status); + if (mi) + *((longlong *)buff)= tmp; + else + var->type= SHOW_UNDEF; + return 0; +} - my_print_help((my_option*) all_options.buffer); - my_print_variables((my_option*) all_options.buffer); - free_root(&mem_root, MYF(0)); +static int show_heartbeat_period(THD *thd, SHOW_VAR *var, char *buff) +{ + Master_info *mi= NULL; + float tmp; + LINT_INIT(tmp); + + var->type= SHOW_CHAR; + var->value= buff; + mysql_mutex_unlock(&LOCK_status); + mysql_mutex_lock(&LOCK_active_mi); + if (master_info_index) + { + mi= master_info_index-> + get_master_info(&thd->variables.default_master_connection, + Sql_condition::WARN_LEVEL_NOTE); + if (mi) + tmp= mi->heartbeat_period; + } + mysql_mutex_unlock(&LOCK_active_mi); + mysql_mutex_lock(&LOCK_status); + if (mi) + sprintf(buff, "%.3f", tmp); + else + var->type= SHOW_UNDEF; + return 0; } -static void usage(void) + +#endif /* HAVE_REPLICATION */ + +static int show_open_tables(THD *thd, SHOW_VAR *var, char *buff) { - DBUG_ENTER("usage"); - if (!(default_charset_info= get_charset_by_csname(default_character_set_name, - MY_CS_PRIMARY, - MYF(MY_WME)))) - exit(1); - if (!default_collation_name) - default_collation_name= (char*) default_charset_info->name; - print_version(); - puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000")); - puts("Starts the MariaDB database server.\n"); - printf("Usage: %s [OPTIONS]\n", my_progname); - if (!opt_verbose) - puts("\nFor more help options (several pages), use mysqld --verbose --help."); - else - { -#ifdef __WIN__ - puts("NT and Win32 specific options:\n\ - --install Install the default service (NT).\n\ - --install-manual Install the default service started manually (NT).\n\ - --install service_name Install an optional service (NT).\n\ - --install-manual service_name Install an optional service started manually (NT).\n\ - --remove Remove the default service from the service list (NT).\n\ - --remove service_name Remove the service_name from the service list (NT).\n\ - --enable-named-pipe Only to be used for the default server (NT).\n\ - --standalone Dummy option to start as a standalone server (NT).\ -"); - puts(""); -#endif - print_defaults(MYSQL_CONFIG_NAME,load_default_groups); - puts(""); - set_ports(); + var->type= SHOW_LONG; + var->value= buff; + *((long *) buff)= (long) tc_records(); + return 0; +} - /* Print out all the options including plugin supplied options */ - print_help(); +static int show_prepared_stmt_count(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + mysql_mutex_lock(&LOCK_prepared_stmt_count); + *((long *)buff)= (long)prepared_stmt_count; + mysql_mutex_unlock(&LOCK_prepared_stmt_count); + return 0; +} - if (! plugins_are_initialized) - { - puts("\n\ -Plugins have parameters that are not reflected in this list\n\ -because execution stopped before plugins were initialized."); - } +static int show_table_definitions(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *) buff)= (long) tdc_records(); + return 0; +} - puts("\n\ -To see what values a running MySQL server is using, type\n\ -'mysqladmin variables' instead of 'mysqld --verbose --help'."); - } - DBUG_VOID_RETURN; + +static int show_flush_commands(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *) buff)= (long) tdc_refresh_version(); + return 0; +} + + +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) +/* Functions relying on CTX */ +static int show_ssl_ctx_sess_accept(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context)); + return 0; +} + +static int show_ssl_ctx_sess_accept_good(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context)); + return 0; +} + +static int show_ssl_ctx_sess_connect_good(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context)); + return 0; } -#endif /*!EMBEDDED_LIBRARY*/ -/** - Initialize MySQL global variables to default values. +static int show_ssl_ctx_sess_accept_renegotiate(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)); + return 0; +} - @note - The reason to set a lot of global variables to zero is to allow one to - restart the embedded server with a clean environment - It's also needed on some exotic platforms where global variables are - not set to 0 when a program starts. +static int show_ssl_ctx_sess_connect_renegotiate(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context)); + return 0; +} - We don't need to set variables refered to in my_long_options - as these are initialized by my_getopt. -*/ +static int show_ssl_ctx_sess_cb_hits(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context)); + return 0; +} -static int mysql_init_variables(void) +static int show_ssl_ctx_sess_hits(THD *thd, SHOW_VAR *var, char *buff) { - /* Things reset to zero */ - opt_skip_slave_start= opt_reckless_slave = 0; - mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; -#if defined(HAVE_REALPATH) && !defined(HAVE_valgrind) && !defined(HAVE_BROKEN_REALPATH) - /* We can only test for sub paths if my_symlink.c is using realpath */ - myisam_test_invalid_symlink= test_if_data_home_dir; -#endif - opt_log= opt_slow_log= 0; - opt_bin_log= opt_bin_log_used= 0; - opt_disable_networking= opt_skip_show_db=0; - opt_skip_name_resolve= 0; - opt_ignore_builtin_innodb= 0; - opt_logname= opt_binlog_index_name= opt_slow_logname= 0; - opt_log_basename= 0; - opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name ! - opt_secure_auth= 0; - opt_bootstrap= opt_myisam_log= 0; - mqh_used= 0; - kill_in_progress= 0; - cleanup_done= 0; - server_id_supplied= 0; - test_flags= select_errors= dropping_tables= ha_open_options=0; - thread_count= thread_running= kill_cached_threads= wake_thread=0; - slave_open_temp_tables= 0; - cached_thread_count= 0; - opt_endinfo= using_udf_functions= 0; - opt_using_transactions= 0; - abort_loop= select_thread_in_use= signal_thread_in_use= 0; - ready_to_exit= shutdown_in_progress= grant_option= 0; - aborted_threads= aborted_connects= 0; - subquery_cache_miss= subquery_cache_hit= 0; - delayed_insert_threads= delayed_insert_writes= delayed_rows_in_use= 0; - delayed_insert_errors= thread_created= 0; - specialflag= 0; - binlog_cache_use= binlog_cache_disk_use= 0; - max_used_connections= slow_launch_threads = 0; - mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0; - prepared_stmt_count= 0; - mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS; - bzero((uchar*) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); - bzero((char *) &global_status_var, sizeof(global_status_var)); - opt_large_pages= 0; - opt_super_large_pages= 0; -#if defined(ENABLED_DEBUG_SYNC) - opt_debug_sync_timeout= 0; -#endif /* defined(ENABLED_DEBUG_SYNC) */ - key_map_full.set_all(); + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context)); + return 0; +} - /* Character sets */ - system_charset_info= &my_charset_utf8_general_ci; - files_charset_info= &my_charset_utf8_general_ci; - national_charset_info= &my_charset_utf8_general_ci; - table_alias_charset= &my_charset_bin; - character_set_filesystem= &my_charset_bin; +static int show_ssl_ctx_sess_cache_full(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context)); + return 0; +} - opt_specialflag= SPECIAL_ENGLISH; - unix_sock= base_ip_sock= extra_ip_sock= MYSQL_INVALID_SOCKET; - mysql_home_ptr= mysql_home; - pidfile_name_ptr= pidfile_name; - log_error_file_ptr= log_error_file; - protocol_version= PROTOCOL_VERSION; - what_to_log= ~ (1L << (uint) COM_TIME); - denied_connections= 0; - executed_events= 0; - global_query_id= thread_id= 1L; - my_atomic_rwlock_init(&global_query_id_lock); - my_atomic_rwlock_init(&thread_running_lock); - my_atomic_rwlock_init(&thread_count_lock); - my_atomic_rwlock_init(&statistics_lock); - strmov(server_version, MYSQL_SERVER_VERSION); - threads.empty(); - thread_cache.empty(); - key_caches.empty(); - if (!(dflt_key_cache= get_or_create_key_cache(default_key_cache_base.str, - default_key_cache_base.length))) - { - sql_print_error("Cannot allocate the keycache"); - return 1; - } +static int show_ssl_ctx_sess_misses(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context)); + return 0; +} - /* set key_cache_hash.default_value = dflt_key_cache */ - multi_keycache_init(); +static int show_ssl_ctx_sess_timeouts(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)); + return 0; +} - /* Set directory paths */ - mysql_real_data_home_len= - strmake_buf(mysql_real_data_home, - get_relative_path(MYSQL_DATADIR)) - mysql_real_data_home; - /* Replication parameters */ - master_info_file= (char*) "master.info", - relay_log_info_file= (char*) "relay-log.info"; - report_user= report_password = report_host= 0; /* TO BE DELETED */ - opt_relay_logname= opt_relaylog_index_name= 0; - slave_retried_transactions= 0; +static int show_ssl_ctx_sess_number(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)); + return 0; +} - /* Variables in libraries */ - charsets_dir= 0; - default_character_set_name= (char*) MYSQL_DEFAULT_CHARSET_NAME; - default_collation_name= compiled_default_collation_name; - character_set_filesystem_name= (char*) "binary"; - lc_messages= (char*) "en_US"; - lc_time_names_name= (char*) "en_US"; - - /* Variables that depends on compile options */ -#ifndef DBUG_OFF - default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", - "d:t:i:o,/tmp/mysqld.trace"); - current_dbug_option= default_dbug_option; -#endif - opt_error_log= IF_WIN(1,0); -#ifdef ENABLED_PROFILING - have_profiling = SHOW_OPTION_YES; -#else - have_profiling = SHOW_OPTION_NO; -#endif +static int show_ssl_ctx_sess_connect(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)); + return 0; +} -#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) - have_ssl=SHOW_OPTION_YES; -#if HAVE_YASSL - have_openssl= SHOW_OPTION_NO; -#else - have_openssl= SHOW_OPTION_YES; -#endif -#else - have_openssl= have_ssl= SHOW_OPTION_NO; -#endif -#ifdef HAVE_BROKEN_REALPATH - have_symlink=SHOW_OPTION_NO; -#else - have_symlink=SHOW_OPTION_YES; -#endif -#ifdef HAVE_DLOPEN - have_dlopen=SHOW_OPTION_YES; -#else - have_dlopen=SHOW_OPTION_NO; -#endif -#ifdef HAVE_QUERY_CACHE - have_query_cache=SHOW_OPTION_YES; -#else - have_query_cache=SHOW_OPTION_NO; -#endif -#ifdef HAVE_SPATIAL - have_geometry=SHOW_OPTION_YES; -#else - have_geometry=SHOW_OPTION_NO; -#endif -#ifdef HAVE_RTREE_KEYS - have_rtree_keys=SHOW_OPTION_YES; -#else - have_rtree_keys=SHOW_OPTION_NO; -#endif -#ifdef HAVE_CRYPT - have_crypt=SHOW_OPTION_YES; -#else - have_crypt=SHOW_OPTION_NO; -#endif -#ifdef HAVE_COMPRESS - have_compress= SHOW_OPTION_YES; -#else - have_compress= SHOW_OPTION_NO; -#endif -#ifdef HAVE_LIBWRAP - libwrapName= NullS; -#endif -#ifdef HAVE_OPENSSL - des_key_file = 0; -#ifndef EMBEDDED_LIBRARY - ssl_acceptor_fd= 0; -#endif /* ! EMBEDDED_LIBRARY */ -#endif /* HAVE_OPENSSL */ -#ifdef HAVE_SMEM - shared_memory_base_name= default_shared_memory_base_name; -#endif +static int show_ssl_ctx_sess_get_cache_size(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)); + return 0; +} -#if defined(__WIN__) - /* Allow Win32 users to move MySQL anywhere */ - { - char prg_dev[LIBLEN]; - char executing_path_name[LIBLEN]; - if (!test_if_hard_path(my_progname)) - { - // we don't want to use GetModuleFileName inside of my_path since - // my_path is a generic path dereferencing function and here we care - // only about the executing binary. - GetModuleFileName(NULL, executing_path_name, sizeof(executing_path_name)); - my_path(prg_dev, executing_path_name, NULL); - } - else - my_path(prg_dev, my_progname, "mysql/bin"); - strcat(prg_dev,"/../"); // Remove 'bin' to get base dir - cleanup_dirname(mysql_home,prg_dev); - } -#else - const char *tmpenv; - if (!(tmpenv = getenv("MY_BASEDIR_VERSION"))) - tmpenv = DEFAULT_MYSQL_HOME; - strmake_buf(mysql_home, tmpenv); -#endif -#ifdef WITH_WSREP - if (WSREP_ON && wsrep_init_vars()) - return 1; -#endif +static int show_ssl_ctx_get_verify_mode(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)); return 0; } -my_bool -mysqld_get_one_option(int optid, - const struct my_option *opt __attribute__((unused)), - char *argument) +static int show_ssl_ctx_get_verify_depth(THD *thd, SHOW_VAR *var, char *buff) { - switch(optid) { - case '#': -#ifndef DBUG_OFF - if (!argument) - argument= (char*) default_dbug_option; - if (argument[0] == '0' && !argument[1]) - { - DEBUGGER_OFF; - break; - } - DEBUGGER_ON; - if (argument[0] == '1' && !argument[1]) - break; - DBUG_SET_INITIAL(argument); - opt_endinfo=1; /* unireg: memory allocation */ -#else - sql_print_warning("'%s' is disabled in this build", opt->name); -#endif - break; - case OPT_DEPRECATED_OPTION: - sql_print_warning("'%s' is deprecated. It does nothing and exists only " - "for compatiblity with old my.cnf files.", - opt->name); - break; - case 'a': - global_system_variables.sql_mode= MODE_ANSI; - global_system_variables.tx_isolation= ISO_SERIALIZABLE; - break; - case 'b': - strmake_buf(mysql_home, argument); - break; - case 'C': - if (default_collation_name == compiled_default_collation_name) - default_collation_name= 0; - break; - case 'h': - strmake_buf(mysql_real_data_home, argument); - /* Correct pointer set by my_getopt (for embedded library) */ - mysql_real_data_home_ptr= mysql_real_data_home; - break; - case 'u': - if (!mysqld_user || !strcmp(mysqld_user, argument)) - mysqld_user= argument; - else - sql_print_warning("Ignoring user change to '%s' because the user was set to '%s' earlier on the command line\n", argument, mysqld_user); - break; - case 'L': - strmake_buf(lc_messages_dir, argument); - break; - case OPT_BINLOG_FORMAT: - binlog_format_used= true; - break; -#include -#ifndef EMBEDDED_LIBRARY - case 'V': - print_version(); - opt_abort= 1; // Abort after parsing all options - break; -#endif /*EMBEDDED_LIBRARY*/ - case 'W': - if (!argument) - global_system_variables.log_warnings++; - else if (argument == disabled_my_option) - global_system_variables.log_warnings= 0L; - else - global_system_variables.log_warnings= atoi(argument); - break; - case 'T': - test_flags= argument ? (uint) atoi(argument) : 0; - opt_endinfo=1; - break; - case (int) OPT_ISAM_LOG: - opt_myisam_log=1; - break; - case (int) OPT_BIN_LOG: - opt_bin_log= test(argument != disabled_my_option); - opt_bin_log_used= 1; - break; - case (int) OPT_LOG_BASENAME: - { - if (opt_log_basename[0] == 0 || strchr(opt_log_basename, FN_EXTCHAR) || - strchr(opt_log_basename,FN_LIBCHAR)) + var->type= SHOW_LONG; + var->value= buff; + *((long *)buff)= (!ssl_acceptor_fd ? 0 : + SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)); + return 0; +} + +static int show_ssl_ctx_get_session_cache_mode(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_CHAR; + if (!ssl_acceptor_fd) + var->value= const_cast("NONE"); + else + switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context)) { - sql_print_error("Wrong argument for --log-basename. It can't be empty or contain '.' or '" FN_DIRSEP "'"); - return 1; + case SSL_SESS_CACHE_OFF: + var->value= const_cast("OFF"); break; + case SSL_SESS_CACHE_CLIENT: + var->value= const_cast("CLIENT"); break; + case SSL_SESS_CACHE_SERVER: + var->value= const_cast("SERVER"); break; + case SSL_SESS_CACHE_BOTH: + var->value= const_cast("BOTH"); break; + case SSL_SESS_CACHE_NO_AUTO_CLEAR: + var->value= const_cast("NO_AUTO_CLEAR"); break; + case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: + var->value= const_cast("NO_INTERNAL_LOOKUP"); break; + default: + var->value= const_cast("Unknown"); break; } - if (log_error_file_ptr != disabled_my_option) - log_error_file_ptr= opt_log_basename; + return 0; +} - make_default_log_name(&opt_logname, ".log", false); - make_default_log_name(&opt_slow_logname, "-slow.log", false); - make_default_log_name(&opt_bin_logname, "-bin", true); - make_default_log_name(&opt_binlog_index_name, "-bin.index", true); - make_default_log_name(&opt_relay_logname, "-relay-bin", true); - make_default_log_name(&opt_relaylog_index_name, "-relay-bin.index", true); +/* + Functions relying on SSL + Note: In the show_ssl_* functions, we need to check if we have a + valid vio-object since this isn't always true, specifically + when session_status or global_status is requested from + inside an Event. + */ +static int show_ssl_get_version(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_CHAR; + if( thd->vio_ok() && thd->net.vio->ssl_arg ) + var->value= const_cast(SSL_get_version((SSL*) thd->net.vio->ssl_arg)); + else + var->value= (char *)""; + return 0; +} - pidfile_name_ptr= pidfile_name; - strmake(pidfile_name, argument, sizeof(pidfile_name)-5); - strmov(fn_ext(pidfile_name),".pid"); +static int show_ssl_session_reused(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + if( thd->vio_ok() && thd->net.vio->ssl_arg ) + *((long *)buff)= (long)SSL_session_reused((SSL*) thd->net.vio->ssl_arg); + else + *((long *)buff)= 0; + return 0; +} - /* check for errors */ - if (!opt_bin_logname || !opt_relaylog_index_name || ! opt_logname || - ! opt_slow_logname || !pidfile_name_ptr) - return 1; // out of memory error - break; - } -#ifdef HAVE_REPLICATION - case (int)OPT_REPLICATE_IGNORE_DB: - { - cur_rpl_filter->add_ignore_db(argument); - break; - } - case (int)OPT_REPLICATE_DO_DB: - { - cur_rpl_filter->add_do_db(argument); - break; - } - case (int)OPT_REPLICATE_REWRITE_DB: - { - /* See also OPT_REWRITE_DB handling in client/mysqlbinlog.cc */ - char* key = argument,*p, *val; +static int show_ssl_get_default_timeout(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + if( thd->vio_ok() && thd->net.vio->ssl_arg ) + *((long *)buff)= (long)SSL_get_default_timeout((SSL*)thd->net.vio->ssl_arg); + else + *((long *)buff)= 0; + return 0; +} - if (!(p= strstr(argument, "->"))) - { - sql_print_error("Bad syntax in replicate-rewrite-db - missing '->'!\n"); - return 1; - } - val= p--; - while (my_isspace(mysqld_charset, *p) && p > argument) - *p-- = 0; - if (p == argument) - { - sql_print_error("Bad syntax in replicate-rewrite-db - empty FROM db!\n"); - return 1; - } - *val= 0; - val+= 2; - while (*val && my_isspace(mysqld_charset, *val)) - val++; - if (!*val) - { - sql_print_error("Bad syntax in replicate-rewrite-db - empty TO db!\n"); - return 1; - } +static int show_ssl_get_verify_mode(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + if( thd->net.vio && thd->net.vio->ssl_arg ) + *((long *)buff)= (long)SSL_get_verify_mode((SSL*)thd->net.vio->ssl_arg); + else + *((long *)buff)= 0; + return 0; +} + +static int show_ssl_get_verify_depth(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + if( thd->vio_ok() && thd->net.vio->ssl_arg ) + *((long *)buff)= (long)SSL_get_verify_depth((SSL*)thd->net.vio->ssl_arg); + else + *((long *)buff)= 0; + return 0; +} - cur_rpl_filter->add_db_rewrite(key, val); - break; - } +static int show_ssl_get_cipher(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_CHAR; + if( thd->vio_ok() && thd->net.vio->ssl_arg ) + var->value= const_cast(SSL_get_cipher((SSL*) thd->net.vio->ssl_arg)); + else + var->value= (char *)""; + return 0; +} - case (int)OPT_BINLOG_IGNORE_DB: - { - binlog_filter->add_ignore_db(argument); - break; - } - case (int)OPT_BINLOG_DO_DB: - { - binlog_filter->add_do_db(argument); - break; - } - case (int)OPT_REPLICATE_DO_TABLE: +static int show_ssl_get_cipher_list(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_CHAR; + var->value= buff; + if (thd->vio_ok() && thd->net.vio->ssl_arg) { - if (cur_rpl_filter->add_do_table(argument)) + int i; + const char *p; + char *end= buff + SHOW_VAR_FUNC_BUFF_SIZE; + for (i=0; (p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i)) && + buff < end; i++) { - sql_print_error("Could not add do table rule '%s'!\n", argument); - return 1; + buff= strnmov(buff, p, end-buff-1); + *buff++= ':'; } - break; + if (i) + buff--; } - case (int)OPT_REPLICATE_WILD_DO_TABLE: + *buff=0; + return 0; +} + + +#ifdef HAVE_YASSL + +static char * +my_asn1_time_to_string(ASN1_TIME *time, char *buf, size_t len) +{ + return yaSSL_ASN1_TIME_to_string(time, buf, len); +} + +#else /* openssl */ + +static char * +my_asn1_time_to_string(ASN1_TIME *time, char *buf, size_t len) +{ + int n_read; + char *res= NULL; + BIO *bio= BIO_new(BIO_s_mem()); + + if (bio == NULL) + return NULL; + + if (!ASN1_TIME_print(bio, time)) + goto end; + + n_read= BIO_read(bio, buf, (int) (len - 1)); + + if (n_read > 0) { - if (cur_rpl_filter->add_wild_do_table(argument)) - { - sql_print_error("Could not add do table rule '%s'!\n", argument); - return 1; - } - break; + buf[n_read]= 0; + res= buf; } - case (int)OPT_REPLICATE_WILD_IGNORE_TABLE: + +end: + BIO_free(bio); + return res; +} + +#endif + + +/** + Handler function for the 'ssl_get_server_not_before' variable + + @param thd the mysql thread structure + @param var the data for the variable + @param[out] buf the string to put the value of the variable into + + @return status + @retval 0 success +*/ + +static int +show_ssl_get_server_not_before(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_CHAR; + if(thd->vio_ok() && thd->net.vio->ssl_arg) { - if (cur_rpl_filter->add_wild_ignore_table(argument)) - { - sql_print_error("Could not add ignore table rule '%s'!\n", argument); + SSL *ssl= (SSL*) thd->net.vio->ssl_arg; + X509 *cert= SSL_get_certificate(ssl); + ASN1_TIME *not_before= X509_get_notBefore(cert); + + var->value= my_asn1_time_to_string(not_before, buff, + SHOW_VAR_FUNC_BUFF_SIZE); + if (!var->value) return 1; - } - break; + var->value= buff; } - case (int)OPT_REPLICATE_IGNORE_TABLE: + else + var->value= empty_c_string; + return 0; +} + + +/** + Handler function for the 'ssl_get_server_not_after' variable + + @param thd the mysql thread structure + @param var the data for the variable + @param[out] buf the string to put the value of the variable into + + @return status + @retval 0 success +*/ + +static int +show_ssl_get_server_not_after(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_CHAR; + if(thd->vio_ok() && thd->net.vio->ssl_arg) { - if (cur_rpl_filter->add_ignore_table(argument)) - { - sql_print_error("Could not add ignore table rule '%s'!\n", argument); - return 1; - } - break; - } -#endif /* HAVE_REPLICATION */ - case (int) OPT_SAFE: - opt_specialflag|= SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC; - delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; - myisam_recover_options= HA_RECOVER_DEFAULT; - ha_open_options&= ~(HA_OPEN_DELAY_KEY_WRITE); -#ifdef HAVE_QUERY_CACHE - query_cache_size=0; -#endif - sql_print_warning("The syntax '--safe-mode' is deprecated and will be " - "removed in a future release."); - break; - case (int) OPT_SKIP_HOST_CACHE: - opt_specialflag|= SPECIAL_NO_HOST_CACHE; - break; - case (int) OPT_SKIP_RESOLVE: - opt_skip_name_resolve= 1; - opt_specialflag|=SPECIAL_NO_RESOLVE; - break; - case (int) OPT_WANT_CORE: - test_flags |= TEST_CORE_ON_SIGNAL; - break; - case OPT_CONSOLE: - if (opt_console) - opt_error_log= 0; // Force logs to stdout - break; - case OPT_BOOTSTRAP: - opt_noacl=opt_bootstrap=1; - break; - case OPT_SERVER_ID: - server_id_supplied = 1; - ::server_id= global_system_variables.server_id; - break; - case OPT_LOWER_CASE_TABLE_NAMES: - lower_case_table_names_used= 1; - break; -#ifdef WITH_WSREP - case OPT_WSREP_START_POSITION: - wsrep_start_position_init (argument); - break; - case OPT_WSREP_SST_AUTH: - wsrep_sst_auth_init (argument); - break; -#endif -#if defined(ENABLED_DEBUG_SYNC) - case OPT_DEBUG_SYNC_TIMEOUT: - /* - Debug Sync Facility. See debug_sync.cc. - Default timeout for WAIT_FOR action. - Default value is zero (facility disabled). - If option is given without an argument, supply a non-zero value. - */ - if (!argument) - { - /* purecov: begin tested */ - opt_debug_sync_timeout= DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT; - /* purecov: end */ - } - break; -#endif /* defined(ENABLED_DEBUG_SYNC) */ - case OPT_ENGINE_CONDITION_PUSHDOWN: - /* - The last of --engine-condition-pushdown and --optimizer_switch on - command line wins (see get_options(). - */ - if (global_system_variables.engine_condition_pushdown) - global_system_variables.optimizer_switch|= - OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN; - else - global_system_variables.optimizer_switch&= - ~OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN; - break; - case OPT_LOG_ERROR: - /* - "No --log-error" == "write errors to stderr", - "--log-error without argument" == "write errors to a file". - */ - if (argument == NULL) /* no argument */ - log_error_file_ptr= const_cast(""); - break; - case OPT_IGNORE_DB_DIRECTORY: - if (*argument == 0) - ignore_db_dirs_reset(); - else - { - if (push_ignored_db_dir(argument)) - { - sql_print_error("Can't start server: " - "cannot process --ignore-db-dir=%.*s", - FN_REFLEN, argument); - return 1; - } - } - break; + SSL *ssl= (SSL*) thd->net.vio->ssl_arg; + X509 *cert= SSL_get_certificate(ssl); + ASN1_TIME *not_after= X509_get_notAfter(cert); - case OPT_PLUGIN_LOAD: - free_list(opt_plugin_load_list_ptr); - /* fall through */ - case OPT_PLUGIN_LOAD_ADD: - opt_plugin_load_list_ptr->push_back(new i_string(argument)); - break; - case OPT_MAX_LONG_DATA_SIZE: - max_long_data_size_used= true; - break; - case OPT_PFS_INSTRUMENT: -#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE -#ifndef EMBEDDED_LIBRARY - /* Parse instrument name and value from argument string */ - char* name = argument,*p, *val; + var->value= my_asn1_time_to_string(not_after, buff, + SHOW_VAR_FUNC_BUFF_SIZE); + if (!var->value) + return 1; + } + else + var->value= empty_c_string; + return 0; +} - /* Assignment required */ - if (!(p= strchr(argument, '='))) - { - my_getopt_error_reporter(WARNING_LEVEL, - "Missing value for performance_schema_instrument " - "'%s'", argument); - return 0; - } +#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ - /* Option value */ - val= p + 1; - if (!*val) - { - my_getopt_error_reporter(WARNING_LEVEL, - "Missing value for performance_schema_instrument " - "'%s'", argument); - return 0; - } +static int show_default_keycache(THD *thd, SHOW_VAR *var, char *buff) +{ + struct st_data { + KEY_CACHE_STATISTICS stats; + SHOW_VAR var[8]; + } *data; + SHOW_VAR *v; - /* Trim leading spaces from instrument name */ - while (*name && my_isspace(mysqld_charset, *name)) - name++; + data=(st_data *)buff; + v= data->var; - /* Trim trailing spaces and slashes from instrument name */ - while (p > argument && (my_isspace(mysqld_charset, p[-1]) || p[-1] == '/')) - p--; - *p= 0; + var->type= SHOW_ARRAY; + var->value= (char*)v; - if (!*name) - { - my_getopt_error_reporter(WARNING_LEVEL, - "Invalid instrument name for " - "performance_schema_instrument '%s'", argument); - return 0; - } + get_key_cache_statistics(dflt_key_cache, 0, &data->stats); - /* Trim leading spaces from option value */ - while (*val && my_isspace(mysqld_charset, *val)) - val++; +#define set_one_keycache_var(X,Y) \ + v->name= X; \ + v->type= SHOW_LONGLONG; \ + v->value= (char*)&data->stats.Y; \ + v++; - /* Trim trailing spaces from option value */ - if ((p= my_strchr(mysqld_charset, val, val+strlen(val), ' ')) != NULL) - *p= 0; + set_one_keycache_var("blocks_not_flushed", blocks_changed); + set_one_keycache_var("blocks_unused", blocks_unused); + set_one_keycache_var("blocks_used", blocks_used); + set_one_keycache_var("blocks_warm", blocks_warm); + set_one_keycache_var("read_requests", read_requests); + set_one_keycache_var("reads", reads); + set_one_keycache_var("write_requests", write_requests); + set_one_keycache_var("writes", writes); - if (!*val) - { - my_getopt_error_reporter(WARNING_LEVEL, - "Invalid value for performance_schema_instrument " - "'%s'", argument); - return 0; - } + v->name= 0; - /* Add instrument name and value to array of configuration options */ - if (add_pfs_instr_to_array(name, val)) - { - my_getopt_error_reporter(WARNING_LEVEL, - "Invalid value for performance_schema_instrument " - "'%s'", argument); - return 0; - } -#endif /* EMBEDDED_LIBRARY */ + DBUG_ASSERT((char*)(v+1) <= buff + SHOW_VAR_FUNC_BUFF_SIZE); + +#undef set_one_keycache_var + + return 0; +} + +#ifdef HAVE_POOL_OF_THREADS +int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_INT; + var->value= buff; + *(int *)buff= tp_get_idle_thread_count(); + return 0; +} +#endif + +/* + Variables shown by SHOW STATUS in alphabetical order +*/ + +SHOW_VAR status_vars[]= { + {"Aborted_clients", (char*) &aborted_threads, SHOW_LONG}, + {"Aborted_connects", (char*) &aborted_connects, SHOW_LONG}, + {"Access_denied_errors", (char*) offsetof(STATUS_VAR, access_denied_errors), SHOW_LONG_STATUS}, + {"Binlog_bytes_written", (char*) offsetof(STATUS_VAR, binlog_bytes_written), SHOW_LONGLONG_STATUS}, + {"Binlog_cache_disk_use", (char*) &binlog_cache_disk_use, SHOW_LONG}, + {"Binlog_cache_use", (char*) &binlog_cache_use, SHOW_LONG}, + {"Binlog_stmt_cache_disk_use",(char*) &binlog_stmt_cache_disk_use, SHOW_LONG}, + {"Binlog_stmt_cache_use", (char*) &binlog_stmt_cache_use, SHOW_LONG}, + {"Busy_time", (char*) offsetof(STATUS_VAR, busy_time), SHOW_DOUBLE_STATUS}, + {"Bytes_received", (char*) offsetof(STATUS_VAR, bytes_received), SHOW_LONGLONG_STATUS}, + {"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONGLONG_STATUS}, + {"Com", (char*) com_status_vars, SHOW_ARRAY}, + {"Compression", (char*) &show_net_compression, SHOW_SIMPLE_FUNC}, + {"Connections", (char*) &thread_id, SHOW_LONG_NOFLUSH}, + {"Connection_errors_accept", (char*) &connection_errors_accept, SHOW_LONG}, + {"Connection_errors_internal", (char*) &connection_errors_internal, SHOW_LONG}, + {"Connection_errors_max_connections", (char*) &connection_errors_max_connection, SHOW_LONG}, + {"Connection_errors_peer_address", (char*) &connection_errors_peer_addr, SHOW_LONG}, + {"Connection_errors_select", (char*) &connection_errors_select, SHOW_LONG}, + {"Connection_errors_tcpwrap", (char*) &connection_errors_tcpwrap, SHOW_LONG}, + {"Cpu_time", (char*) offsetof(STATUS_VAR, cpu_time), SHOW_DOUBLE_STATUS}, + {"Created_tmp_disk_tables", (char*) offsetof(STATUS_VAR, created_tmp_disk_tables_), SHOW_LONG_STATUS}, + {"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG}, + {"Created_tmp_tables", (char*) offsetof(STATUS_VAR, created_tmp_tables_), SHOW_LONG_STATUS}, + {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, + {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_NOFLUSH}, + {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, + {"Empty_queries", (char*) offsetof(STATUS_VAR, empty_queries), SHOW_LONG_STATUS}, + {"Executed_events", (char*) &executed_events, SHOW_LONG_NOFLUSH }, + {"Executed_triggers", (char*) offsetof(STATUS_VAR, executed_triggers), SHOW_LONG_STATUS}, + {"Feature_dynamic_columns", (char*) offsetof(STATUS_VAR, feature_dynamic_columns), SHOW_LONG_STATUS}, + {"Feature_fulltext", (char*) offsetof(STATUS_VAR, feature_fulltext), SHOW_LONG_STATUS}, + {"Feature_gis", (char*) offsetof(STATUS_VAR, feature_gis), SHOW_LONG_STATUS}, + {"Feature_locale", (char*) offsetof(STATUS_VAR, feature_locale), SHOW_LONG_STATUS}, + {"Feature_subquery", (char*) offsetof(STATUS_VAR, feature_subquery), SHOW_LONG_STATUS}, + {"Feature_timezone", (char*) offsetof(STATUS_VAR, feature_timezone), SHOW_LONG_STATUS}, + {"Feature_trigger", (char*) offsetof(STATUS_VAR, feature_trigger), SHOW_LONG_STATUS}, + {"Feature_xml", (char*) offsetof(STATUS_VAR, feature_xml), SHOW_LONG_STATUS}, + {"Flush_commands", (char*) &show_flush_commands, SHOW_SIMPLE_FUNC}, + {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, + {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, + {"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS}, + {"Handler_external_lock", (char*) offsetof(STATUS_VAR, ha_external_lock_count), SHOW_LONGLONG_STATUS}, + {"Handler_icp_attempts", (char*) offsetof(STATUS_VAR, ha_icp_attempts), SHOW_LONG_STATUS}, + {"Handler_icp_match", (char*) offsetof(STATUS_VAR, ha_icp_match), SHOW_LONG_STATUS}, + {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_mrr_init_count), SHOW_LONG_STATUS}, + {"Handler_mrr_key_refills", (char*) offsetof(STATUS_VAR, ha_mrr_key_refills_count), SHOW_LONG_STATUS}, + {"Handler_mrr_rowid_refills",(char*) offsetof(STATUS_VAR, ha_mrr_rowid_refills_count), SHOW_LONG_STATUS}, + {"Handler_prepare", (char*) offsetof(STATUS_VAR, ha_prepare_count), SHOW_LONG_STATUS}, + {"Handler_read_first", (char*) offsetof(STATUS_VAR, ha_read_first_count), SHOW_LONG_STATUS}, + {"Handler_read_key", (char*) offsetof(STATUS_VAR, ha_read_key_count), SHOW_LONG_STATUS}, + {"Handler_read_last", (char*) offsetof(STATUS_VAR, ha_read_last_count), SHOW_LONG_STATUS}, + {"Handler_read_next", (char*) offsetof(STATUS_VAR, ha_read_next_count), SHOW_LONG_STATUS}, + {"Handler_read_prev", (char*) offsetof(STATUS_VAR, ha_read_prev_count), SHOW_LONG_STATUS}, + {"Handler_read_rnd", (char*) offsetof(STATUS_VAR, ha_read_rnd_count), SHOW_LONG_STATUS}, + {"Handler_read_rnd_deleted", (char*) offsetof(STATUS_VAR, ha_read_rnd_deleted_count), SHOW_LONG_STATUS}, + {"Handler_read_rnd_next", (char*) offsetof(STATUS_VAR, ha_read_rnd_next_count), SHOW_LONG_STATUS}, + {"Handler_rollback", (char*) offsetof(STATUS_VAR, ha_rollback_count), SHOW_LONG_STATUS}, + {"Handler_savepoint", (char*) offsetof(STATUS_VAR, ha_savepoint_count), SHOW_LONG_STATUS}, + {"Handler_savepoint_rollback",(char*) offsetof(STATUS_VAR, ha_savepoint_rollback_count), SHOW_LONG_STATUS}, + {"Handler_tmp_update", (char*) offsetof(STATUS_VAR, ha_tmp_update_count), SHOW_LONG_STATUS}, + {"Handler_tmp_write", (char*) offsetof(STATUS_VAR, ha_tmp_write_count), SHOW_LONG_STATUS}, + {"Handler_update", (char*) offsetof(STATUS_VAR, ha_update_count), SHOW_LONG_STATUS}, + {"Handler_write", (char*) offsetof(STATUS_VAR, ha_write_count), SHOW_LONG_STATUS}, + {"Key", (char*) &show_default_keycache, SHOW_FUNC}, + {"Last_query_cost", (char*) offsetof(STATUS_VAR, last_query_cost), SHOW_DOUBLE_STATUS}, + {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, + {"Memory_used", (char*) offsetof(STATUS_VAR, memory_used), SHOW_LONGLONG_STATUS}, + {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_NOFLUSH}, + {"Open_files", (char*) &my_file_opened, SHOW_LONG_NOFLUSH}, + {"Open_streams", (char*) &my_stream_opened, SHOW_LONG_NOFLUSH}, + {"Open_table_definitions", (char*) &show_table_definitions, SHOW_SIMPLE_FUNC}, + {"Open_tables", (char*) &show_open_tables, SHOW_SIMPLE_FUNC}, + {"Opened_files", (char*) &my_file_total_opened, SHOW_LONG_NOFLUSH}, + {"Opened_plugin_libraries", (char*) &dlopen_count, SHOW_LONG}, + {"Opened_table_definitions", (char*) offsetof(STATUS_VAR, opened_shares), SHOW_LONG_STATUS}, + {"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS}, + {"Opened_views", (char*) offsetof(STATUS_VAR, opened_views), SHOW_LONG_STATUS}, + {"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_SIMPLE_FUNC}, + {"Rows_sent", (char*) offsetof(STATUS_VAR, rows_sent), SHOW_LONGLONG_STATUS}, + {"Rows_read", (char*) offsetof(STATUS_VAR, rows_read), SHOW_LONGLONG_STATUS}, + {"Rows_tmp_read", (char*) offsetof(STATUS_VAR, rows_tmp_read), SHOW_LONGLONG_STATUS}, +#ifdef HAVE_QUERY_CACHE + {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_NOFLUSH}, + {"Qcache_free_memory", (char*) &query_cache.free_memory, SHOW_LONG_NOFLUSH}, + {"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG}, + {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG}, + {"Qcache_lowmem_prunes", (char*) &query_cache.lowmem_prunes, SHOW_LONG}, + {"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG}, + {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_NOFLUSH}, + {"Qcache_total_blocks", (char*) &query_cache.total_blocks, SHOW_LONG_NOFLUSH}, +#endif /*HAVE_QUERY_CACHE*/ + {"Queries", (char*) &show_queries, SHOW_SIMPLE_FUNC}, + {"Questions", (char*) offsetof(STATUS_VAR, questions), SHOW_LONG_STATUS}, +#ifdef HAVE_REPLICATION + {"Rpl_status", (char*) &show_rpl_status, SHOW_SIMPLE_FUNC}, +#endif + {"Select_full_join", (char*) offsetof(STATUS_VAR, select_full_join_count_), SHOW_LONG_STATUS}, + {"Select_full_range_join", (char*) offsetof(STATUS_VAR, select_full_range_join_count_), SHOW_LONG_STATUS}, + {"Select_range", (char*) offsetof(STATUS_VAR, select_range_count_), SHOW_LONG_STATUS}, + {"Select_range_check", (char*) offsetof(STATUS_VAR, select_range_check_count_), SHOW_LONG_STATUS}, + {"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count_), SHOW_LONG_STATUS}, + {"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG}, +#ifdef HAVE_REPLICATION + {"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_SIMPLE_FUNC}, + {"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_SIMPLE_FUNC}, + {"Slave_retried_transactions",(char*)&slave_retried_transactions, SHOW_LONG}, + {"Slave_running", (char*) &show_slave_running, SHOW_SIMPLE_FUNC}, +#endif + {"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG}, + {"Slow_queries", (char*) offsetof(STATUS_VAR, long_query_count), SHOW_LONG_STATUS}, + {"Sort_merge_passes", (char*) offsetof(STATUS_VAR, filesort_merge_passes_), SHOW_LONG_STATUS}, + {"Sort_range", (char*) offsetof(STATUS_VAR, filesort_range_count_), SHOW_LONG_STATUS}, + {"Sort_rows", (char*) offsetof(STATUS_VAR, filesort_rows_), SHOW_LONG_STATUS}, + {"Sort_scan", (char*) offsetof(STATUS_VAR, filesort_scan_count_), SHOW_LONG_STATUS}, +#ifdef HAVE_OPENSSL +#ifndef EMBEDDED_LIBRARY + {"Ssl_accept_renegotiates", (char*) &show_ssl_ctx_sess_accept_renegotiate, SHOW_SIMPLE_FUNC}, + {"Ssl_accepts", (char*) &show_ssl_ctx_sess_accept, SHOW_SIMPLE_FUNC}, + {"Ssl_callback_cache_hits", (char*) &show_ssl_ctx_sess_cb_hits, SHOW_SIMPLE_FUNC}, + {"Ssl_cipher", (char*) &show_ssl_get_cipher, SHOW_SIMPLE_FUNC}, + {"Ssl_cipher_list", (char*) &show_ssl_get_cipher_list, SHOW_SIMPLE_FUNC}, + {"Ssl_client_connects", (char*) &show_ssl_ctx_sess_connect, SHOW_SIMPLE_FUNC}, + {"Ssl_connect_renegotiates", (char*) &show_ssl_ctx_sess_connect_renegotiate, SHOW_SIMPLE_FUNC}, + {"Ssl_ctx_verify_depth", (char*) &show_ssl_ctx_get_verify_depth, SHOW_SIMPLE_FUNC}, + {"Ssl_ctx_verify_mode", (char*) &show_ssl_ctx_get_verify_mode, SHOW_SIMPLE_FUNC}, + {"Ssl_default_timeout", (char*) &show_ssl_get_default_timeout, SHOW_SIMPLE_FUNC}, + {"Ssl_finished_accepts", (char*) &show_ssl_ctx_sess_accept_good, SHOW_SIMPLE_FUNC}, + {"Ssl_finished_connects", (char*) &show_ssl_ctx_sess_connect_good, SHOW_SIMPLE_FUNC}, + {"Ssl_server_not_after", (char*) &show_ssl_get_server_not_after, SHOW_SIMPLE_FUNC}, + {"Ssl_server_not_before", (char*) &show_ssl_get_server_not_before, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_hits", (char*) &show_ssl_ctx_sess_hits, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_misses", (char*) &show_ssl_ctx_sess_misses, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_mode", (char*) &show_ssl_ctx_get_session_cache_mode, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_overflows", (char*) &show_ssl_ctx_sess_cache_full, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_size", (char*) &show_ssl_ctx_sess_get_cache_size, SHOW_SIMPLE_FUNC}, + {"Ssl_session_cache_timeouts", (char*) &show_ssl_ctx_sess_timeouts, SHOW_SIMPLE_FUNC}, + {"Ssl_sessions_reused", (char*) &show_ssl_session_reused, SHOW_SIMPLE_FUNC}, + {"Ssl_used_session_cache_entries",(char*) &show_ssl_ctx_sess_number, SHOW_SIMPLE_FUNC}, + {"Ssl_verify_depth", (char*) &show_ssl_get_verify_depth, SHOW_SIMPLE_FUNC}, + {"Ssl_verify_mode", (char*) &show_ssl_get_verify_mode, SHOW_SIMPLE_FUNC}, + {"Ssl_version", (char*) &show_ssl_get_version, SHOW_SIMPLE_FUNC}, +#endif +#endif /* HAVE_OPENSSL */ + {"Syncs", (char*) &my_sync_count, SHOW_LONG_NOFLUSH}, + /* + Expression cache used only for caching subqueries now, so its statistic + variables we call subquery_cache*. + */ + {"Subquery_cache_hit", (char*) &subquery_cache_hit, SHOW_LONG}, + {"Subquery_cache_miss", (char*) &subquery_cache_miss, SHOW_LONG}, + {"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG}, + {"Table_locks_waited", (char*) &locks_waited, SHOW_LONG}, +#ifdef HAVE_MMAP + {"Tc_log_max_pages_used", (char*) &tc_log_max_pages_used, SHOW_LONG}, + {"Tc_log_page_size", (char*) &tc_log_page_size, SHOW_LONG_NOFLUSH}, + {"Tc_log_page_waits", (char*) &tc_log_page_waits, SHOW_LONG}, +#endif +#ifdef HAVE_POOL_OF_THREADS + {"Threadpool_idle_threads", (char *) &show_threadpool_idle_threads, SHOW_SIMPLE_FUNC}, + {"Threadpool_threads", (char *) &tp_stats.num_worker_threads, SHOW_INT}, +#endif + {"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_NOFLUSH}, + {"Threads_connected", (char*) &connection_count, SHOW_INT}, + {"Threads_created", (char*) &thread_created, SHOW_LONG_NOFLUSH}, + {"Threads_running", (char*) &thread_running, SHOW_INT}, + {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, +#ifdef ENABLED_PROFILING + {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC}, #endif - break; - } #ifdef WITH_WSREP - mysql_mutex_init(key_LOCK_wsrep_ready, - &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL); - mysql_mutex_init(key_LOCK_wsrep_sst, - &LOCK_wsrep_sst, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL); - mysql_mutex_init(key_LOCK_wsrep_sst_init, - &LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL); - mysql_mutex_init(key_LOCK_wsrep_rollback, - &LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL); - mysql_mutex_init(key_LOCK_wsrep_replaying, - &LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST); - mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL); - mysql_mutex_init(key_LOCK_wsrep_slave_threads, - &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST); + {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL}, + {"wsrep_ready", (char*) &wsrep_ready, SHOW_BOOL}, + {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, + {"wsrep_cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, + {"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, + {"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG}, + {"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG}, + {"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, + {"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, + {"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, + {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC}, #endif - return 0; + {NullS, NullS, SHOW_LONG} +}; + +static bool add_terminator(DYNAMIC_ARRAY *options) +{ + my_option empty_element= {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}; + return insert_dynamic(options, (uchar *)&empty_element); } +static bool add_many_options(DYNAMIC_ARRAY *options, my_option *list, + size_t elements) +{ + for (my_option *opt= list; opt < list + elements; opt++) + if (insert_dynamic(options, opt)) + return 1; + return 0; +} -/** Handle arguments for multiple key caches. */ +#ifndef EMBEDDED_LIBRARY +static void print_version(void) +{ + set_server_version(); -C_MODE_START + printf("%s Ver %s for %s on %s (%s)\n",my_progname, + server_version,SYSTEM_TYPE,MACHINE_TYPE, MYSQL_COMPILATION_COMMENT); +} -static void* -mysql_getopt_value(const char *name, uint length, - const struct my_option *option, int *error) +/** Compares two options' names, treats - and _ the same */ +static int option_cmp(my_option *a, my_option *b) { - if (error) - *error= 0; - switch (option->id) { - case OPT_KEY_BUFFER_SIZE: - case OPT_KEY_CACHE_BLOCK_SIZE: - case OPT_KEY_CACHE_DIVISION_LIMIT: - case OPT_KEY_CACHE_AGE_THRESHOLD: - case OPT_KEY_CACHE_PARTITIONS: + const char *sa= a->name; + const char *sb= b->name; + for (; *sa || *sb; sa++, sb++) { - KEY_CACHE *key_cache; - if (!(key_cache= get_or_create_key_cache(name, length))) + if (*sa < *sb) { - if (error) - *error= EXIT_OUT_OF_MEMORY; - return 0; - } - switch (option->id) { - case OPT_KEY_BUFFER_SIZE: - return &key_cache->param_buff_size; - case OPT_KEY_CACHE_BLOCK_SIZE: - return &key_cache->param_block_size; - case OPT_KEY_CACHE_DIVISION_LIMIT: - return &key_cache->param_division_limit; - case OPT_KEY_CACHE_AGE_THRESHOLD: - return &key_cache->param_age_threshold; - case OPT_KEY_CACHE_PARTITIONS: - return (uchar**) &key_cache->param_partitions; + if (*sa == '-' && *sb == '_') + continue; + else + return -1; } - } - case OPT_REPLICATE_DO_DB: - case OPT_REPLICATE_DO_TABLE: - case OPT_REPLICATE_IGNORE_DB: - case OPT_REPLICATE_IGNORE_TABLE: - case OPT_REPLICATE_WILD_DO_TABLE: - case OPT_REPLICATE_WILD_IGNORE_TABLE: - case OPT_REPLICATE_REWRITE_DB: - { - /* Store current filter for mysqld_get_one_option() */ - if (!(cur_rpl_filter= get_or_create_rpl_filter(name, length))) + if (*sa > *sb) { - if (error) - *error= EXIT_OUT_OF_MEMORY; + if (*sa == '_' && *sb == '-') + continue; + else + return 1; } - return 0; - } - } - return option->value; -} - -static void option_error_reporter(enum loglevel level, const char *format, ...) -{ - va_list args; - va_start(args, format); - - /* Don't print warnings for --loose options during bootstrap */ - if (level == ERROR_LEVEL || !opt_bootstrap || - global_system_variables.log_warnings) - { - vprint_msg_to_log(level, format, args); } - va_end(args); + DBUG_ASSERT(a->name == b->name); + return 0; } -C_MODE_END - -/** - Get server options from the command line, - and perform related server initializations. - @param [in, out] argc_ptr command line options (count) - @param [in, out] argv_ptr command line options (values) - @return 0 on success - - @todo - - FIXME add EXIT_TOO_MANY_ARGUMENTS to "mysys_err.h" and return that code? -*/ -static int get_options(int *argc_ptr, char ***argv_ptr) +static void print_help() { - int ho_error; - - my_getopt_register_get_addr(mysql_getopt_value); - my_getopt_error_reporter= option_error_reporter; + MEM_ROOT mem_root; + init_alloc_root(&mem_root, 4096, 4096, MYF(0)); - /* prepare all_options array */ - my_init_dynamic_array(&all_options, sizeof(my_option), - array_elements(my_long_options), - array_elements(my_long_options)/4, MYF(0)); - add_many_options(&all_options, my_long_options, array_elements(my_long_options)); - sys_var_add_options(&all_options, 0); + pop_dynamic(&all_options); + add_many_options(&all_options, pfs_early_options, + array_elements(pfs_early_options)); + sys_var_add_options(&all_options, sys_var::PARSE_EARLY); + add_plugin_options(&all_options, &mem_root); + sort_dynamic(&all_options, (qsort_cmp) option_cmp); add_terminator(&all_options); - /* Skip unknown options so that they may be processed later by plugins */ - my_getopt_skip_unknown= TRUE; + my_print_help((my_option*) all_options.buffer); + my_print_variables((my_option*) all_options.buffer); - if ((ho_error= handle_options(argc_ptr, argv_ptr, (my_option*)(all_options.buffer), - mysqld_get_one_option))) - return ho_error; + free_root(&mem_root, MYF(0)); +} - if (!opt_help) - delete_dynamic(&all_options); +static void usage(void) +{ + DBUG_ENTER("usage"); + if (!(default_charset_info= get_charset_by_csname(default_character_set_name, + MY_CS_PRIMARY, + MYF(MY_WME)))) + exit(1); + if (!default_collation_name) + default_collation_name= (char*) default_charset_info->name; + print_version(); + puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000")); + puts("Starts the MariaDB database server.\n"); + printf("Usage: %s [OPTIONS]\n", my_progname); + if (!opt_verbose) + puts("\nFor more help options (several pages), use mysqld --verbose --help."); else - opt_abort= 1; - - /* Add back the program name handle_options removes */ - (*argc_ptr)++; - (*argv_ptr)--; + { +#ifdef __WIN__ + puts("NT and Win32 specific options:\n\ + --install Install the default service (NT).\n\ + --install-manual Install the default service started manually (NT).\n\ + --install service_name Install an optional service (NT).\n\ + --install-manual service_name Install an optional service started manually (NT).\n\ + --remove Remove the default service from the service list (NT).\n\ + --remove service_name Remove the service_name from the service list (NT).\n\ + --enable-named-pipe Only to be used for the default server (NT).\n\ + --standalone Dummy option to start as a standalone server (NT).\ +"); + puts(""); +#endif + print_defaults(MYSQL_CONFIG_NAME,load_default_groups); + puts(""); + set_ports(); - /* - Options have been parsed. Now some of them need additional special - handling, like custom value checking, checking of incompatibilites - between options, setting of multiple variables, etc. - Do them here. - */ + /* Print out all the options including plugin supplied options */ + print_help(); - if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes || - opt_log_slow_slave_statements) && - !opt_slow_log) - sql_print_warning("options --log-slow-admin-statements, --log-queries-not-using-indexes and --log-slow-slave-statements have no effect if --log_slow_queries is not set"); - if (global_system_variables.net_buffer_length > - global_system_variables.max_allowed_packet) + if (! plugins_are_initialized) { - sql_print_warning("net_buffer_length (%lu) is set to be larger " - "than max_allowed_packet (%lu). Please rectify.", - global_system_variables.net_buffer_length, - global_system_variables.max_allowed_packet); + puts("\n\ +Plugins have parameters that are not reflected in this list\n\ +because execution stopped before plugins were initialized."); } - if (log_error_file_ptr != disabled_my_option) - opt_error_log= 1; - else - log_error_file_ptr= const_cast(""); + puts("\n\ +To see what values a running MySQL server is using, type\n\ +'mysqladmin variables' instead of 'mysqld --verbose --help'."); + } + DBUG_VOID_RETURN; +} +#endif /*!EMBEDDED_LIBRARY*/ - opt_init_connect.length=strlen(opt_init_connect.str); - opt_init_slave.length=strlen(opt_init_slave.str); +/** + Initialize MySQL global variables to default values. - if (global_system_variables.low_priority_updates) - thr_upgraded_concurrent_insert_lock= TL_WRITE_LOW_PRIORITY; + @note + The reason to set a lot of global variables to zero is to allow one to + restart the embedded server with a clean environment + It's also needed on some exotic platforms where global variables are + not set to 0 when a program starts. - if (ft_boolean_check_syntax_string((uchar*) ft_boolean_syntax)) + We don't need to set variables refered to in my_long_options + as these are initialized by my_getopt. +*/ + +static int mysql_init_variables(void) +{ + /* Things reset to zero */ + opt_skip_slave_start= opt_reckless_slave = 0; + mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; +#if defined(HAVE_REALPATH) && !defined(HAVE_valgrind) && !defined(HAVE_BROKEN_REALPATH) + /* We can only test for sub paths if my_symlink.c is using realpath */ + myisam_test_invalid_symlink= test_if_data_home_dir; +#endif + opt_log= opt_slow_log= 0; + opt_bin_log= opt_bin_log_used= 0; + opt_disable_networking= opt_skip_show_db=0; + opt_skip_name_resolve= 0; + opt_ignore_builtin_innodb= 0; + opt_logname= opt_binlog_index_name= opt_slow_logname= 0; + opt_log_basename= 0; + opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name ! + opt_secure_auth= 0; + opt_bootstrap= opt_myisam_log= 0; + mqh_used= 0; + kill_in_progress= 0; + cleanup_done= 0; + server_id_supplied= 0; + test_flags= select_errors= dropping_tables= ha_open_options=0; + thread_count= thread_running= kill_cached_threads= wake_thread=0; + slave_open_temp_tables= 0; + cached_thread_count= 0; + opt_endinfo= using_udf_functions= 0; + opt_using_transactions= 0; + abort_loop= select_thread_in_use= signal_thread_in_use= 0; + ready_to_exit= shutdown_in_progress= grant_option= 0; + aborted_threads= aborted_connects= 0; + subquery_cache_miss= subquery_cache_hit= 0; + delayed_insert_threads= delayed_insert_writes= delayed_rows_in_use= 0; + delayed_insert_errors= thread_created= 0; + specialflag= 0; + binlog_cache_use= binlog_cache_disk_use= 0; + max_used_connections= slow_launch_threads = 0; + mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0; + prepared_stmt_count= 0; + mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS; + bzero((uchar*) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); + bzero((char *) &global_status_var, sizeof(global_status_var)); + opt_large_pages= 0; + opt_super_large_pages= 0; +#if defined(ENABLED_DEBUG_SYNC) + opt_debug_sync_timeout= 0; +#endif /* defined(ENABLED_DEBUG_SYNC) */ + key_map_full.set_all(); + + /* Character sets */ + system_charset_info= &my_charset_utf8_general_ci; + files_charset_info= &my_charset_utf8_general_ci; + national_charset_info= &my_charset_utf8_general_ci; + table_alias_charset= &my_charset_bin; + character_set_filesystem= &my_charset_bin; + + opt_specialflag= SPECIAL_ENGLISH; + unix_sock= base_ip_sock= extra_ip_sock= MYSQL_INVALID_SOCKET; + mysql_home_ptr= mysql_home; + pidfile_name_ptr= pidfile_name; + log_error_file_ptr= log_error_file; + protocol_version= PROTOCOL_VERSION; + what_to_log= ~ (1L << (uint) COM_TIME); + denied_connections= 0; + executed_events= 0; + global_query_id= thread_id= 1L; + my_atomic_rwlock_init(&global_query_id_lock); + my_atomic_rwlock_init(&thread_running_lock); + my_atomic_rwlock_init(&thread_count_lock); + my_atomic_rwlock_init(&statistics_lock); + strmov(server_version, MYSQL_SERVER_VERSION); + threads.empty(); + thread_cache.empty(); + key_caches.empty(); + if (!(dflt_key_cache= get_or_create_key_cache(default_key_cache_base.str, + default_key_cache_base.length))) { - sql_print_error("Invalid ft-boolean-syntax string: %s\n", - ft_boolean_syntax); + sql_print_error("Cannot allocate the keycache"); return 1; } - if (opt_disable_networking) - mysqld_port= mysqld_extra_port= 0; - - if (opt_skip_show_db) - opt_specialflag|= SPECIAL_SKIP_SHOW_DB; + /* set key_cache_hash.default_value = dflt_key_cache */ + multi_keycache_init(); - if (myisam_flush) - flush_time= 0; + /* Set directory paths */ + mysql_real_data_home_len= + strmake_buf(mysql_real_data_home, + get_relative_path(MYSQL_DATADIR)) - mysql_real_data_home; + /* Replication parameters */ + master_info_file= (char*) "master.info", + relay_log_info_file= (char*) "relay-log.info"; + report_user= report_password = report_host= 0; /* TO BE DELETED */ + opt_relay_logname= opt_relaylog_index_name= 0; + slave_retried_transactions= 0; -#ifdef HAVE_REPLICATION - if (opt_slave_skip_errors) - init_slave_skip_errors(opt_slave_skip_errors); + /* Variables in libraries */ + charsets_dir= 0; + default_character_set_name= (char*) MYSQL_DEFAULT_CHARSET_NAME; + default_collation_name= compiled_default_collation_name; + character_set_filesystem_name= (char*) "binary"; + lc_messages= (char*) "en_US"; + lc_time_names_name= (char*) "en_US"; + + /* Variables that depends on compile options */ +#ifndef DBUG_OFF + default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", + "d:t:i:o,/tmp/mysqld.trace"); + current_dbug_option= default_dbug_option; #endif - - if (global_system_variables.max_join_size == HA_POS_ERROR) - global_system_variables.option_bits|= OPTION_BIG_SELECTS; - else - global_system_variables.option_bits&= ~OPTION_BIG_SELECTS; - - // Synchronize @@global.autocommit on --autocommit - const ulonglong turn_bit_on= opt_autocommit ? - OPTION_AUTOCOMMIT : OPTION_NOT_AUTOCOMMIT; - global_system_variables.option_bits= - (global_system_variables.option_bits & - ~(OPTION_NOT_AUTOCOMMIT | OPTION_AUTOCOMMIT)) | turn_bit_on; - - global_system_variables.sql_mode= - expand_sql_mode(global_system_variables.sql_mode); -#if !defined(HAVE_REALPATH) || defined(HAVE_BROKEN_REALPATH) - my_use_symdir=0; - my_disable_symlinks=1; - have_symlink=SHOW_OPTION_NO; + opt_error_log= IF_WIN(1,0); +#ifdef ENABLED_PROFILING + have_profiling = SHOW_OPTION_YES; #else - if (!my_use_symdir) - { - my_disable_symlinks=1; - have_symlink=SHOW_OPTION_DISABLED; - } + have_profiling = SHOW_OPTION_NO; #endif - if (opt_debugging) - { - /* Allow break with SIGINT, no core or stack trace */ - test_flags|= TEST_SIGINT; - opt_stack_trace= 1; - test_flags&= ~TEST_CORE_ON_SIGNAL; - } - /* Set global MyISAM variables from delay_key_write_options */ - fix_delay_key_write(0, 0, OPT_GLOBAL); -#ifndef EMBEDDED_LIBRARY - if (mysqld_chroot) - set_root(mysqld_chroot); +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + have_ssl=SHOW_OPTION_YES; +#if HAVE_YASSL + have_openssl= SHOW_OPTION_NO; #else - thread_handling = SCHEDULER_NO_THREADS; - max_allowed_packet= global_system_variables.max_allowed_packet; - net_buffer_length= global_system_variables.net_buffer_length; + have_openssl= SHOW_OPTION_YES; #endif - if (fix_paths()) - return 1; - - /* - Set some global variables from the global_system_variables - In most cases the global variables will not be used - */ - my_disable_locking= myisam_single_user= test(opt_external_locking == 0); - my_default_record_cache_size=global_system_variables.read_buff_size; - - /* - Log mysys errors when we don't have a thd or thd->log_all_errors is set - (recovery) to the log. This is mainly useful for debugging strange system - errors. - */ - if (global_system_variables.log_warnings >= 10) - my_global_flags= MY_WME | ME_JUST_INFO; - /* Log all errors not handled by thd->handle_error() to my_message_sql() */ - if (global_system_variables.log_warnings >= 11) - my_global_flags|= ME_NOREFRESH; - if (my_assert_on_error) - debug_assert_if_crashed_table= 1; - - global_system_variables.long_query_time= (ulonglong) - (global_system_variables.long_query_time_double * 1e6); - - if (opt_short_log_format) - opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT; - - if (init_global_datetime_format(MYSQL_TIMESTAMP_DATE, - &global_date_format) || - init_global_datetime_format(MYSQL_TIMESTAMP_TIME, - &global_time_format) || - init_global_datetime_format(MYSQL_TIMESTAMP_DATETIME, - &global_datetime_format)) - return 1; - -#ifdef EMBEDDED_LIBRARY - one_thread_scheduler(thread_scheduler); - one_thread_scheduler(extra_thread_scheduler); #else - -#ifdef _WIN32 - /* workaround: disable thread pool on XP */ - if (GetProcAddress(GetModuleHandle("kernel32"),"CreateThreadpool") == 0 && - thread_handling > SCHEDULER_NO_THREADS) - thread_handling = SCHEDULER_ONE_THREAD_PER_CONNECTION; + have_openssl= have_ssl= SHOW_OPTION_NO; +#endif +#ifdef HAVE_BROKEN_REALPATH + have_symlink=SHOW_OPTION_NO; +#else + have_symlink=SHOW_OPTION_YES; +#endif +#ifdef HAVE_DLOPEN + have_dlopen=SHOW_OPTION_YES; +#else + have_dlopen=SHOW_OPTION_NO; +#endif +#ifdef HAVE_QUERY_CACHE + have_query_cache=SHOW_OPTION_YES; +#else + have_query_cache=SHOW_OPTION_NO; #endif - - if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION) - one_thread_per_connection_scheduler(thread_scheduler, &max_connections, - &connection_count); - else if (thread_handling == SCHEDULER_NO_THREADS) - one_thread_scheduler(thread_scheduler); - else - pool_of_threads_scheduler(thread_scheduler, &max_connections, - &connection_count); - - one_thread_per_connection_scheduler(extra_thread_scheduler, - &extra_max_connections, - &extra_connection_count); +#ifdef HAVE_SPATIAL + have_geometry=SHOW_OPTION_YES; +#else + have_geometry=SHOW_OPTION_NO; +#endif +#ifdef HAVE_RTREE_KEYS + have_rtree_keys=SHOW_OPTION_YES; +#else + have_rtree_keys=SHOW_OPTION_NO; +#endif +#ifdef HAVE_CRYPT + have_crypt=SHOW_OPTION_YES; +#else + have_crypt=SHOW_OPTION_NO; +#endif +#ifdef HAVE_COMPRESS + have_compress= SHOW_OPTION_YES; +#else + have_compress= SHOW_OPTION_NO; +#endif +#ifdef HAVE_LIBWRAP + libwrapName= NullS; +#endif +#ifdef HAVE_OPENSSL + des_key_file = 0; +#ifndef EMBEDDED_LIBRARY + ssl_acceptor_fd= 0; +#endif /* ! EMBEDDED_LIBRARY */ +#endif /* HAVE_OPENSSL */ +#ifdef HAVE_SMEM + shared_memory_base_name= default_shared_memory_base_name; #endif - global_system_variables.engine_condition_pushdown= - test(global_system_variables.optimizer_switch & - OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN); - - opt_readonly= read_only; - - /* - If max_long_data_size is not specified explicitly use - value of max_allowed_packet. - */ - if (!max_long_data_size_used) - max_long_data_size= global_system_variables.max_allowed_packet; - - /* Remember if max_user_connections was 0 at startup */ - max_user_connections_checking= global_system_variables.max_user_connections != 0; - +#if defined(__WIN__) + /* Allow Win32 users to move MySQL anywhere */ { - sys_var *max_relay_log_size_var, *max_binlog_size_var; - /* If max_relay_log_size is 0, then set it to max_binlog_size */ - if (!global_system_variables.max_relay_log_size) - global_system_variables.max_relay_log_size= max_binlog_size; - - /* - Fix so that DEFAULT and limit checking works with max_relay_log_size - (Yes, this is a hack, but it's required as the definition of - max_relay_log_size allows it to be set to 0). - */ - max_relay_log_size_var= intern_find_sys_var("max_relay_log_size", 0); - max_binlog_size_var= intern_find_sys_var("max_binlog_size", 0); - if (max_binlog_size_var && max_relay_log_size_var) + char prg_dev[LIBLEN]; + char executing_path_name[LIBLEN]; + if (!test_if_hard_path(my_progname)) { - max_relay_log_size_var->option.min_value= - max_binlog_size_var->option.min_value; - max_relay_log_size_var->option.def_value= - max_binlog_size_var->option.def_value; + // we don't want to use GetModuleFileName inside of my_path since + // my_path is a generic path dereferencing function and here we care + // only about the executing binary. + GetModuleFileName(NULL, executing_path_name, sizeof(executing_path_name)); + my_path(prg_dev, executing_path_name, NULL); } + else + my_path(prg_dev, my_progname, "mysql/bin"); + strcat(prg_dev,"/../"); // Remove 'bin' to get base dir + cleanup_dirname(mysql_home,prg_dev); } +#else + const char *tmpenv; + if (!(tmpenv = getenv("MY_BASEDIR_VERSION"))) + tmpenv = DEFAULT_MYSQL_HOME; + strmake_buf(mysql_home, tmpenv); +#endif +#ifdef WITH_WSREP + if (WSREP_ON && wsrep_init_vars()) + return 1; +#endif return 0; } - -/* - Create version name for running mysqld version - We automaticly add suffixes -debug, -embedded and -log to the version - name to make the version more descriptive. - (MYSQL_SERVER_SUFFIX is set by the compilation environment) -*/ - -void set_server_version(void) +my_bool +mysqld_get_one_option(int optid, + const struct my_option *opt __attribute__((unused)), + char *argument) { - char *end= strxmov(server_version, MYSQL_SERVER_VERSION, - MYSQL_SERVER_SUFFIX_STR, NullS); -#ifdef EMBEDDED_LIBRARY - end= strmov(end, "-embedded"); -#endif + switch(optid) { + case '#': #ifndef DBUG_OFF - if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug")) - end= strmov(end, "-debug"); + if (!argument) + argument= (char*) default_dbug_option; + if (argument[0] == '0' && !argument[1]) + { + DEBUGGER_OFF; + break; + } + DEBUGGER_ON; + if (argument[0] == '1' && !argument[1]) + break; + DBUG_SET_INITIAL(argument); + opt_endinfo=1; /* unireg: memory allocation */ +#else + sql_print_warning("'%s' is disabled in this build", opt->name); #endif - if (opt_log || opt_slow_log || opt_bin_log) - strmov(end, "-log"); // This may slow down system -} - - -static char *get_relative_path(const char *path) -{ - if (test_if_hard_path(path) && - is_prefix(path,DEFAULT_MYSQL_HOME) && - strcmp(DEFAULT_MYSQL_HOME,FN_ROOTDIR)) - { - path+=(uint) strlen(DEFAULT_MYSQL_HOME); - while (*path == FN_LIBCHAR || *path == FN_LIBCHAR2) - path++; - } - return (char*) path; -} - - -/** - Fix filename and replace extension where 'dir' is relative to - mysql_real_data_home. - @return - 1 if len(path) > FN_REFLEN -*/ - -bool -fn_format_relative_to_data_home(char * to, const char *name, - const char *dir, const char *extension) -{ - char tmp_path[FN_REFLEN]; - if (!test_if_hard_path(dir)) + break; + case OPT_DEPRECATED_OPTION: + sql_print_warning("'%s' is deprecated. It does nothing and exists only " + "for compatiblity with old my.cnf files.", + opt->name); + break; + case 'a': + global_system_variables.sql_mode= MODE_ANSI; + global_system_variables.tx_isolation= ISO_SERIALIZABLE; + break; + case 'b': + strmake_buf(mysql_home, argument); + break; + case 'C': + if (default_collation_name == compiled_default_collation_name) + default_collation_name= 0; + break; + case 'h': + strmake_buf(mysql_real_data_home, argument); + /* Correct pointer set by my_getopt (for embedded library) */ + mysql_real_data_home_ptr= mysql_real_data_home; + break; + case 'u': + if (!mysqld_user || !strcmp(mysqld_user, argument)) + mysqld_user= argument; + else + sql_print_warning("Ignoring user change to '%s' because the user was set to '%s' earlier on the command line\n", argument, mysqld_user); + break; + case 'L': + strmake_buf(lc_messages_dir, argument); + break; + case OPT_BINLOG_FORMAT: + binlog_format_used= true; + break; +#include +#ifndef EMBEDDED_LIBRARY + case 'V': + print_version(); + opt_abort= 1; // Abort after parsing all options + break; +#endif /*EMBEDDED_LIBRARY*/ + case 'W': + if (!argument) + global_system_variables.log_warnings++; + else if (argument == disabled_my_option) + global_system_variables.log_warnings= 0L; + else + global_system_variables.log_warnings= atoi(argument); + break; + case 'T': + test_flags= argument ? (uint) atoi(argument) : 0; + opt_endinfo=1; + break; + case (int) OPT_ISAM_LOG: + opt_myisam_log=1; + break; + case (int) OPT_BIN_LOG: + opt_bin_log= test(argument != disabled_my_option); + opt_bin_log_used= 1; + break; + case (int) OPT_LOG_BASENAME: { - strxnmov(tmp_path,sizeof(tmp_path)-1, mysql_real_data_home, - dir, NullS); - dir=tmp_path; - } - return !fn_format(to, name, dir, extension, - MY_APPEND_EXT | MY_UNPACK_FILENAME | MY_SAFE_PATH); -} - + if (opt_log_basename[0] == 0 || strchr(opt_log_basename, FN_EXTCHAR) || + strchr(opt_log_basename,FN_LIBCHAR)) + { + sql_print_error("Wrong argument for --log-basename. It can't be empty or contain '.' or '" FN_DIRSEP "'"); + return 1; + } + if (log_error_file_ptr != disabled_my_option) + log_error_file_ptr= opt_log_basename; -/** - Test a file path to determine if the path is compatible with the secure file - path restriction. - - @param path null terminated character string + make_default_log_name(&opt_logname, ".log", false); + make_default_log_name(&opt_slow_logname, "-slow.log", false); + make_default_log_name(&opt_bin_logname, "-bin", true); + make_default_log_name(&opt_binlog_index_name, "-bin.index", true); + make_default_log_name(&opt_relay_logname, "-relay-bin", true); + make_default_log_name(&opt_relaylog_index_name, "-relay-bin.index", true); - @return - @retval TRUE The path is secure - @retval FALSE The path isn't secure -*/ + pidfile_name_ptr= pidfile_name; + strmake(pidfile_name, argument, sizeof(pidfile_name)-5); + strmov(fn_ext(pidfile_name),".pid"); -bool is_secure_file_path(char *path) -{ - char buff1[FN_REFLEN], buff2[FN_REFLEN]; - size_t opt_secure_file_priv_len; - /* - All paths are secure if opt_secure_file_path is 0 - */ - if (!opt_secure_file_priv) - return TRUE; + /* check for errors */ + if (!opt_bin_logname || !opt_relaylog_index_name || ! opt_logname || + ! opt_slow_logname || !pidfile_name_ptr) + return 1; // out of memory error + break; + } +#ifdef HAVE_REPLICATION + case (int)OPT_REPLICATE_IGNORE_DB: + { + cur_rpl_filter->add_ignore_db(argument); + break; + } + case (int)OPT_REPLICATE_DO_DB: + { + cur_rpl_filter->add_do_db(argument); + break; + } + case (int)OPT_REPLICATE_REWRITE_DB: + { + /* See also OPT_REWRITE_DB handling in client/mysqlbinlog.cc */ + char* key = argument,*p, *val; - opt_secure_file_priv_len= strlen(opt_secure_file_priv); + if (!(p= strstr(argument, "->"))) + { + sql_print_error("Bad syntax in replicate-rewrite-db - missing '->'!\n"); + return 1; + } + val= p--; + while (my_isspace(mysqld_charset, *p) && p > argument) + *p-- = 0; + if (p == argument) + { + sql_print_error("Bad syntax in replicate-rewrite-db - empty FROM db!\n"); + return 1; + } + *val= 0; + val+= 2; + while (*val && my_isspace(mysqld_charset, *val)) + val++; + if (!*val) + { + sql_print_error("Bad syntax in replicate-rewrite-db - empty TO db!\n"); + return 1; + } - if (strlen(path) >= FN_REFLEN) - return FALSE; + cur_rpl_filter->add_db_rewrite(key, val); + break; + } - if (my_realpath(buff1, path, 0)) + case (int)OPT_BINLOG_IGNORE_DB: { - /* - The supplied file path might have been a file and not a directory. - */ - size_t length= dirname_length(path); // Guaranteed to be < FN_REFLEN - memcpy(buff2, path, length); - buff2[length]= '\0'; - if (length == 0 || my_realpath(buff1, buff2, 0)) - return FALSE; + binlog_filter->add_ignore_db(argument); + break; } - convert_dirname(buff2, buff1, NullS); - if (!lower_case_file_system) + case (int)OPT_BINLOG_DO_DB: { - if (strncmp(opt_secure_file_priv, buff2, opt_secure_file_priv_len)) - return FALSE; + binlog_filter->add_do_db(argument); + break; } - else + case (int)OPT_REPLICATE_DO_TABLE: { - if (files_charset_info->coll->strnncoll(files_charset_info, - (uchar *) buff2, strlen(buff2), - (uchar *) opt_secure_file_priv, - opt_secure_file_priv_len, - TRUE)) - return FALSE; + if (cur_rpl_filter->add_do_table(argument)) + { + sql_print_error("Could not add do table rule '%s'!\n", argument); + return 1; + } + break; } - return TRUE; -} + case (int)OPT_REPLICATE_WILD_DO_TABLE: + { + if (cur_rpl_filter->add_wild_do_table(argument)) + { + sql_print_error("Could not add do table rule '%s'!\n", argument); + return 1; + } + break; + } + case (int)OPT_REPLICATE_WILD_IGNORE_TABLE: + { + if (cur_rpl_filter->add_wild_ignore_table(argument)) + { + sql_print_error("Could not add ignore table rule '%s'!\n", argument); + return 1; + } + break; + } + case (int)OPT_REPLICATE_IGNORE_TABLE: + { + if (cur_rpl_filter->add_ignore_table(argument)) + { + sql_print_error("Could not add ignore table rule '%s'!\n", argument); + return 1; + } + break; + } +#endif /* HAVE_REPLICATION */ + case (int) OPT_SAFE: + opt_specialflag|= SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC; + delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; + myisam_recover_options= HA_RECOVER_DEFAULT; + ha_open_options&= ~(HA_OPEN_DELAY_KEY_WRITE); +#ifdef HAVE_QUERY_CACHE + query_cache_size=0; +#endif + sql_print_warning("The syntax '--safe-mode' is deprecated and will be " + "removed in a future release."); + break; + case (int) OPT_SKIP_HOST_CACHE: + opt_specialflag|= SPECIAL_NO_HOST_CACHE; + break; + case (int) OPT_SKIP_RESOLVE: + opt_skip_name_resolve= 1; + opt_specialflag|=SPECIAL_NO_RESOLVE; + break; + case (int) OPT_WANT_CORE: + test_flags |= TEST_CORE_ON_SIGNAL; + break; + case OPT_CONSOLE: + if (opt_console) + opt_error_log= 0; // Force logs to stdout + break; + case OPT_BOOTSTRAP: + opt_noacl=opt_bootstrap=1; + break; + case OPT_SERVER_ID: + server_id_supplied = 1; + ::server_id= global_system_variables.server_id; + break; + case OPT_LOWER_CASE_TABLE_NAMES: + lower_case_table_names_used= 1; + break; +#ifdef WITH_WSREP + case OPT_WSREP_START_POSITION: + wsrep_start_position_init (argument); + break; + case OPT_WSREP_SST_AUTH: + wsrep_sst_auth_init (argument); + break; +#endif +#if defined(ENABLED_DEBUG_SYNC) + case OPT_DEBUG_SYNC_TIMEOUT: + /* + Debug Sync Facility. See debug_sync.cc. + Default timeout for WAIT_FOR action. + Default value is zero (facility disabled). + If option is given without an argument, supply a non-zero value. + */ + if (!argument) + { + /* purecov: begin tested */ + opt_debug_sync_timeout= DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT; + /* purecov: end */ + } + break; +#endif /* defined(ENABLED_DEBUG_SYNC) */ + case OPT_ENGINE_CONDITION_PUSHDOWN: + /* + The last of --engine-condition-pushdown and --optimizer_switch on + command line wins (see get_options(). + */ + if (global_system_variables.engine_condition_pushdown) + global_system_variables.optimizer_switch|= + OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN; + else + global_system_variables.optimizer_switch&= + ~OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN; + break; + case OPT_LOG_ERROR: + /* + "No --log-error" == "write errors to stderr", + "--log-error without argument" == "write errors to a file". + */ + if (argument == NULL) /* no argument */ + log_error_file_ptr= const_cast(""); + break; + case OPT_IGNORE_DB_DIRECTORY: + if (*argument == 0) + ignore_db_dirs_reset(); + else + { + if (push_ignored_db_dir(argument)) + { + sql_print_error("Can't start server: " + "cannot process --ignore-db-dir=%.*s", + FN_REFLEN, argument); + return 1; + } + } + break; + case OPT_PLUGIN_LOAD: + free_list(opt_plugin_load_list_ptr); + /* fall through */ + case OPT_PLUGIN_LOAD_ADD: + opt_plugin_load_list_ptr->push_back(new i_string(argument)); + break; + case OPT_MAX_LONG_DATA_SIZE: + max_long_data_size_used= true; + break; + case OPT_PFS_INSTRUMENT: +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE +#ifndef EMBEDDED_LIBRARY + /* Parse instrument name and value from argument string */ + char* name = argument,*p, *val; -static int fix_paths(void) -{ - char buff[FN_REFLEN],*pos; - DBUG_ENTER("fix_paths"); + /* Assignment required */ + if (!(p= strchr(argument, '='))) + { + my_getopt_error_reporter(WARNING_LEVEL, + "Missing value for performance_schema_instrument " + "'%s'", argument); + return 0; + } - convert_dirname(mysql_home,mysql_home,NullS); - /* Resolve symlinks to allow 'mysql_home' to be a relative symlink */ - my_realpath(mysql_home,mysql_home,MYF(0)); - /* Ensure that mysql_home ends in FN_LIBCHAR */ - pos=strend(mysql_home); - if (pos[-1] != FN_LIBCHAR) - { - pos[0]= FN_LIBCHAR; - pos[1]= 0; - } - convert_dirname(lc_messages_dir, lc_messages_dir, NullS); - convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); - (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir - (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); - (void) my_load_path(pidfile_name, pidfile_name_ptr, mysql_real_data_home); + /* Option value */ + val= p + 1; + if (!*val) + { + my_getopt_error_reporter(WARNING_LEVEL, + "Missing value for performance_schema_instrument " + "'%s'", argument); + return 0; + } - convert_dirname(opt_plugin_dir, opt_plugin_dir_ptr ? opt_plugin_dir_ptr : - get_relative_path(PLUGINDIR), NullS); - (void) my_load_path(opt_plugin_dir, opt_plugin_dir, mysql_home); - opt_plugin_dir_ptr= opt_plugin_dir; - pidfile_name_ptr= pidfile_name; + /* Trim leading spaces from instrument name */ + while (*name && my_isspace(mysqld_charset, *name)) + name++; - my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); - mysql_unpacked_real_data_home_len= - (int) strlen(mysql_unpacked_real_data_home); - if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) - --mysql_unpacked_real_data_home_len; + /* Trim trailing spaces and slashes from instrument name */ + while (p > argument && (my_isspace(mysqld_charset, p[-1]) || p[-1] == '/')) + p--; + *p= 0; - char *sharedir=get_relative_path(SHAREDIR); - if (test_if_hard_path(sharedir)) - strmake_buf(buff, sharedir); /* purecov: tested */ - else - strxnmov(buff,sizeof(buff)-1,mysql_home,sharedir,NullS); - convert_dirname(buff,buff,NullS); - (void) my_load_path(lc_messages_dir, lc_messages_dir, buff); + if (!*name) + { + my_getopt_error_reporter(WARNING_LEVEL, + "Invalid instrument name for " + "performance_schema_instrument '%s'", argument); + return 0; + } - /* If --character-sets-dir isn't given, use shared library dir */ - if (charsets_dir) - strmake_buf(mysql_charsets_dir, charsets_dir); - else - strxnmov(mysql_charsets_dir, sizeof(mysql_charsets_dir)-1, buff, - CHARSET_DIR, NullS); - (void) my_load_path(mysql_charsets_dir, mysql_charsets_dir, buff); - convert_dirname(mysql_charsets_dir, mysql_charsets_dir, NullS); - charsets_dir=mysql_charsets_dir; + /* Trim leading spaces from option value */ + while (*val && my_isspace(mysqld_charset, *val)) + val++; - if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir)) - DBUG_RETURN(1); - if (!opt_mysql_tmpdir) - opt_mysql_tmpdir= mysql_tmpdir; -#ifdef HAVE_REPLICATION - if (!slave_load_tmpdir) - slave_load_tmpdir= mysql_tmpdir; -#endif /* HAVE_REPLICATION */ - /* - Convert the secure-file-priv option to system format, allowing - a quick strcmp to check if read or write is in an allowed dir - */ - if (opt_secure_file_priv) - { - if (*opt_secure_file_priv == 0) + /* Trim trailing spaces from option value */ + if ((p= my_strchr(mysqld_charset, val, val+strlen(val), ' ')) != NULL) + *p= 0; + + if (!*val) { - my_free(opt_secure_file_priv); - opt_secure_file_priv= 0; + my_getopt_error_reporter(WARNING_LEVEL, + "Invalid value for performance_schema_instrument " + "'%s'", argument); + return 0; } - else + + /* Add instrument name and value to array of configuration options */ + if (add_pfs_instr_to_array(name, val)) { - if (strlen(opt_secure_file_priv) >= FN_REFLEN) - opt_secure_file_priv[FN_REFLEN-1]= '\0'; - if (my_realpath(buff, opt_secure_file_priv, 0)) - { - sql_print_warning("Failed to normalize the argument for --secure-file-priv."); - DBUG_RETURN(1); - } - char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE)); - convert_dirname(secure_file_real_path, buff, NullS); - my_free(opt_secure_file_priv); - opt_secure_file_priv= secure_file_real_path; + my_getopt_error_reporter(WARNING_LEVEL, + "Invalid value for performance_schema_instrument " + "'%s'", argument); + return 0; } +#endif /* EMBEDDED_LIBRARY */ +#endif + break; } - DBUG_RETURN(0); + return 0; } -/** - Check if file system used for databases is case insensitive. - @param dir_name Directory to test +/** Handle arguments for multiple key caches. */ - @retval -1 Don't know (Test failed) - @retval 0 File system is case sensitive - @retval 1 File system is case insensitive -*/ +C_MODE_START -static int test_if_case_insensitive(const char *dir_name) +static void* +mysql_getopt_value(const char *name, uint length, + const struct my_option *option, int *error) { - int result= 0; - File file; - char buff[FN_REFLEN], buff2[FN_REFLEN]; - MY_STAT stat_info; - DBUG_ENTER("test_if_case_insensitive"); - - fn_format(buff, glob_hostname, dir_name, ".lower-test", - MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); - fn_format(buff2, glob_hostname, dir_name, ".LOWER-TEST", - MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); - mysql_file_delete(key_file_casetest, buff2, MYF(0)); - if ((file= mysql_file_create(key_file_casetest, - buff, 0666, O_RDWR, MYF(0))) < 0) + if (error) + *error= 0; + switch (option->id) { + case OPT_KEY_BUFFER_SIZE: + case OPT_KEY_CACHE_BLOCK_SIZE: + case OPT_KEY_CACHE_DIVISION_LIMIT: + case OPT_KEY_CACHE_AGE_THRESHOLD: + case OPT_KEY_CACHE_PARTITIONS: { - if (!opt_abort) - sql_print_warning("Can't create test file %s", buff); - DBUG_RETURN(-1); + KEY_CACHE *key_cache; + if (!(key_cache= get_or_create_key_cache(name, length))) + { + if (error) + *error= EXIT_OUT_OF_MEMORY; + return 0; + } + switch (option->id) { + case OPT_KEY_BUFFER_SIZE: + return &key_cache->param_buff_size; + case OPT_KEY_CACHE_BLOCK_SIZE: + return &key_cache->param_block_size; + case OPT_KEY_CACHE_DIVISION_LIMIT: + return &key_cache->param_division_limit; + case OPT_KEY_CACHE_AGE_THRESHOLD: + return &key_cache->param_age_threshold; + case OPT_KEY_CACHE_PARTITIONS: + return (uchar**) &key_cache->param_partitions; + } } - mysql_file_close(file, MYF(0)); - if (mysql_file_stat(key_file_casetest, buff2, &stat_info, MYF(0))) - result= 1; // Can access file - mysql_file_delete(key_file_casetest, buff, MYF(MY_WME)); - DBUG_PRINT("exit", ("result: %d", result)); - DBUG_RETURN(result); -} -#ifndef EMBEDDED_LIBRARY - -/** - Create file to store pid number. -*/ -static void create_pid_file() -{ - File file; - if ((file= mysql_file_create(key_file_pid, pidfile_name, 0664, - O_WRONLY | O_TRUNC, MYF(MY_WME))) >= 0) + case OPT_REPLICATE_DO_DB: + case OPT_REPLICATE_DO_TABLE: + case OPT_REPLICATE_IGNORE_DB: + case OPT_REPLICATE_IGNORE_TABLE: + case OPT_REPLICATE_WILD_DO_TABLE: + case OPT_REPLICATE_WILD_IGNORE_TABLE: + case OPT_REPLICATE_REWRITE_DB: { - char buff[MAX_BIGINT_WIDTH + 1], *end; - end= int10_to_str((long) getpid(), buff, 10); - *end++= '\n'; - if (!mysql_file_write(file, (uchar*) buff, (uint) (end-buff), - MYF(MY_WME | MY_NABP))) + /* Store current filter for mysqld_get_one_option() */ + if (!(cur_rpl_filter= get_or_create_rpl_filter(name, length))) { - mysql_file_close(file, MYF(0)); - pid_file_created= true; - return; + if (error) + *error= EXIT_OUT_OF_MEMORY; } - mysql_file_close(file, MYF(0)); + return 0; } - sql_perror("Can't start server: can't create PID file"); - exit(1); + } + return option->value; } -#endif /* EMBEDDED_LIBRARY */ - -#ifdef WITH_WSREP -typedef void (*wsrep_thd_processor_fun)(THD *); -pthread_handler_t start_wsrep_THD(void *arg) +static void option_error_reporter(enum loglevel level, const char *format, ...) { - THD *thd; - wsrep_thd_processor_fun processor= (wsrep_thd_processor_fun)arg; + va_list args; + va_start(args, format); - if (my_thread_init()) + /* Don't print warnings for --loose options during bootstrap */ + if (level == ERROR_LEVEL || !opt_bootstrap || + global_system_variables.log_warnings) { - WSREP_ERROR("Could not initialize thread"); - return(NULL); + vprint_msg_to_log(level, format, args); } + va_end(args); +} - if (!(thd= new THD(true))) - { - return(NULL); - } - mysql_mutex_lock(&LOCK_thread_count); - thd->thread_id=thread_id++; +C_MODE_END - thd->real_id=pthread_self(); // Keep purify happy - thread_count++; - thread_created++; - threads.append(thd); +/** + Get server options from the command line, + and perform related server initializations. + @param [in, out] argc_ptr command line options (count) + @param [in, out] argv_ptr command line options (values) + @return 0 on success + + @todo + - FIXME add EXIT_TOO_MANY_ARGUMENTS to "mysys_err.h" and return that code? +*/ +static int get_options(int *argc_ptr, char ***argv_ptr) +{ + int ho_error; - my_net_init(&thd->net,(st_vio*) 0, MYF(0)); + my_getopt_register_get_addr(mysql_getopt_value); + my_getopt_error_reporter= option_error_reporter; - DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id)); - thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer(); - (void) mysql_mutex_unlock(&LOCK_thread_count); + /* prepare all_options array */ + my_init_dynamic_array(&all_options, sizeof(my_option), + array_elements(my_long_options), + array_elements(my_long_options)/4, MYF(0)); + add_many_options(&all_options, my_long_options, array_elements(my_long_options)); + sys_var_add_options(&all_options, 0); + add_terminator(&all_options); - /* from bootstrap()... */ - thd->bootstrap=1; - thd->max_client_packet_length= thd->net.max_packet; - thd->security_ctx->master_access= ~(ulong)0; + /* Skip unknown options so that they may be processed later by plugins */ + my_getopt_skip_unknown= TRUE; - /* from handle_one_connection... */ - pthread_detach_this_thread(); + if ((ho_error= handle_options(argc_ptr, argv_ptr, (my_option*)(all_options.buffer), + mysqld_get_one_option))) + return ho_error; - mysql_thread_set_psi_id(thd->thread_id); - thd->thr_create_utime= microsecond_interval_timer(); - if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0)) - { - close_connection(thd, ER_OUT_OF_RESOURCES, 1); - statistic_increment(aborted_connects,&LOCK_status); - MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); + if (!opt_help) + delete_dynamic(&all_options); + else + opt_abort= 1; - return(NULL); - } + /* Add back the program name handle_options removes */ + (*argc_ptr)++; + (*argv_ptr)--; -// /* - handle_one_connection() is normally the only way a thread would - start and would always be on the very high end of the stack , - therefore, the thread stack always starts at the address of the - first local variable of handle_one_connection, which is thd. We - need to know the start of the stack so that we could check for - stack overruns. + Options have been parsed. Now some of them need additional special + handling, like custom value checking, checking of incompatibilites + between options, setting of multiple variables, etc. + Do them here. */ - DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n", - (long long)thd->thread_id)); - /* now that we've called my_thread_init(), it is safe to call DBUG_* */ - thd->thread_stack= (char*) &thd; - if (thd->store_globals()) + if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes || + opt_log_slow_slave_statements) && + !opt_slow_log) + sql_print_warning("options --log-slow-admin-statements, --log-queries-not-using-indexes and --log-slow-slave-statements have no effect if --log_slow_queries is not set"); + if (global_system_variables.net_buffer_length > + global_system_variables.max_allowed_packet) { - close_connection(thd, ER_OUT_OF_RESOURCES, 1); - statistic_increment(aborted_connects,&LOCK_status); - MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0)); - delete thd; - - return(NULL); + sql_print_warning("net_buffer_length (%lu) is set to be larger " + "than max_allowed_packet (%lu). Please rectify.", + global_system_variables.net_buffer_length, + global_system_variables.max_allowed_packet); } - thd->system_thread= SYSTEM_THREAD_SLAVE_SQL; - thd->security_ctx->skip_grants(); + if (log_error_file_ptr != disabled_my_option) + opt_error_log= 1; + else + log_error_file_ptr= const_cast(""); - /* handle_one_connection() again... */ - //thd->version= refresh_version; - thd->proc_info= 0; - thd->set_command(COM_SLEEP); - thd->set_time(); - thd->init_for_queries(); + opt_init_connect.length=strlen(opt_init_connect.str); + opt_init_slave.length=strlen(opt_init_slave.str); - mysql_mutex_lock(&LOCK_connection_count); - ++connection_count; - mysql_mutex_unlock(&LOCK_connection_count); + if (global_system_variables.low_priority_updates) + thr_upgraded_concurrent_insert_lock= TL_WRITE_LOW_PRIORITY; - mysql_mutex_lock(&LOCK_thread_count); - wsrep_running_threads++; - mysql_cond_signal(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); + if (ft_boolean_check_syntax_string((uchar*) ft_boolean_syntax)) + { + sql_print_error("Invalid ft-boolean-syntax string: %s\n", + ft_boolean_syntax); + return 1; + } - processor(thd); + if (opt_disable_networking) + mysqld_port= mysqld_extra_port= 0; - close_connection(thd, 0, 1); + if (opt_skip_show_db) + opt_specialflag|= SPECIAL_SKIP_SHOW_DB; - mysql_mutex_lock(&LOCK_thread_count); - wsrep_running_threads--; - mysql_cond_signal(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); + if (myisam_flush) + flush_time= 0; - // Note: We can't call THD destructor without crashing - // if plugins have not been initialized. However, in most of the - // cases this means that pre SE initialization SST failed and - // we are going to exit anyway. - if (plugins_are_initialized) - { - net_end(&thd->net); - MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1)); - } +#ifdef HAVE_REPLICATION + if (opt_slave_skip_errors) + init_slave_skip_errors(opt_slave_skip_errors); +#endif + + if (global_system_variables.max_join_size == HA_POS_ERROR) + global_system_variables.option_bits|= OPTION_BIG_SELECTS; else - { - // TODO: lightweight cleanup to get rid of: - // 'Error in my_thread_global_end(): 2 threads didn't exit' - // at server shutdown - } + global_system_variables.option_bits&= ~OPTION_BIG_SELECTS; - if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) - { - mysql_mutex_lock(&LOCK_thread_count); - delete thd; - thread_count--; - mysql_mutex_unlock(&LOCK_thread_count); - } - return(NULL); -} + // Synchronize @@global.autocommit on --autocommit + const ulonglong turn_bit_on= opt_autocommit ? + OPTION_AUTOCOMMIT : OPTION_NOT_AUTOCOMMIT; + global_system_variables.option_bits= + (global_system_variables.option_bits & + ~(OPTION_NOT_AUTOCOMMIT | OPTION_AUTOCOMMIT)) | turn_bit_on; -void wsrep_create_rollbacker() -{ - if (wsrep_provider && strcasecmp(wsrep_provider, "none")) + global_system_variables.sql_mode= + expand_sql_mode(global_system_variables.sql_mode); +#if !defined(HAVE_REALPATH) || defined(HAVE_BROKEN_REALPATH) + my_use_symdir=0; + my_disable_symlinks=1; + have_symlink=SHOW_OPTION_NO; +#else + if (!my_use_symdir) { - pthread_t hThread; - /* create rollbacker */ - if (pthread_create( &hThread, &connection_attrib, - start_wsrep_THD, (void*)wsrep_rollback_process)) - WSREP_WARN("Can't create thread to manage wsrep rollback"); + my_disable_symlinks=1; + have_symlink=SHOW_OPTION_DISABLED; } -} - -void wsrep_create_appliers(long threads) -{ - if (!wsrep_connected) +#endif + if (opt_debugging) { - /* see wsrep_replication_start() for the logic */ - if (wsrep_cluster_address && strlen(wsrep_cluster_address) && - wsrep_provider && strcasecmp(wsrep_provider, "none")) - { - WSREP_ERROR("Trying to launch slave threads before creating " - "connection at '%s'", wsrep_cluster_address); - assert(0); - } - return; + /* Allow break with SIGINT, no core or stack trace */ + test_flags|= TEST_SIGINT; + opt_stack_trace= 1; + test_flags&= ~TEST_CORE_ON_SIGNAL; } + /* Set global MyISAM variables from delay_key_write_options */ + fix_delay_key_write(0, 0, OPT_GLOBAL); - long wsrep_threads=0; - pthread_t hThread; - while (wsrep_threads++ < threads) { - if (pthread_create( - &hThread, &connection_attrib, - start_wsrep_THD, (void*)wsrep_replication_process)) - WSREP_WARN("Can't create thread to manage wsrep replication"); - } -} -/**/ -static bool abort_replicated(THD *thd) -{ - bool ret_code= false; - if (thd->wsrep_query_state== QUERY_COMMITTING) - { - if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id); +#ifndef EMBEDDED_LIBRARY + if (mysqld_chroot) + set_root(mysqld_chroot); +#else + thread_handling = SCHEDULER_NO_THREADS; + max_allowed_packet= global_system_variables.max_allowed_packet; + net_buffer_length= global_system_variables.net_buffer_length; +#endif + if (fix_paths()) + return 1; - (void)wsrep_abort_thd(thd, thd, TRUE); - ret_code= true; - } - return ret_code; -} -/**/ -static inline bool is_client_connection(THD *thd) -{ - return (thd->wsrep_client_thread && thd->variables.wsrep_on); -} + /* + Set some global variables from the global_system_variables + In most cases the global variables will not be used + */ + my_disable_locking= myisam_single_user= test(opt_external_locking == 0); + my_default_record_cache_size=global_system_variables.read_buff_size; + + /* + Log mysys errors when we don't have a thd or thd->log_all_errors is set + (recovery) to the log. This is mainly useful for debugging strange system + errors. + */ + if (global_system_variables.log_warnings >= 10) + my_global_flags= MY_WME | ME_JUST_INFO; + /* Log all errors not handled by thd->handle_error() to my_message_sql() */ + if (global_system_variables.log_warnings >= 11) + my_global_flags|= ME_NOREFRESH; + if (my_assert_on_error) + debug_assert_if_crashed_table= 1; + + global_system_variables.long_query_time= (ulonglong) + (global_system_variables.long_query_time_double * 1e6); + + if (opt_short_log_format) + opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT; + + if (init_global_datetime_format(MYSQL_TIMESTAMP_DATE, + &global_date_format) || + init_global_datetime_format(MYSQL_TIMESTAMP_TIME, + &global_time_format) || + init_global_datetime_format(MYSQL_TIMESTAMP_DATETIME, + &global_datetime_format)) + return 1; -static inline bool is_replaying_connection(THD *thd) -{ - bool ret; +#ifdef EMBEDDED_LIBRARY + one_thread_scheduler(thread_scheduler); + one_thread_scheduler(extra_thread_scheduler); +#else - mysql_mutex_lock(&thd->LOCK_wsrep_thd); - ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false; - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); +#ifdef _WIN32 + /* workaround: disable thread pool on XP */ + if (GetProcAddress(GetModuleHandle("kernel32"),"CreateThreadpool") == 0 && + thread_handling > SCHEDULER_NO_THREADS) + thread_handling = SCHEDULER_ONE_THREAD_PER_CONNECTION; +#endif - return ret; -} + if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION) + one_thread_per_connection_scheduler(thread_scheduler, &max_connections, + &connection_count); + else if (thread_handling == SCHEDULER_NO_THREADS) + one_thread_scheduler(thread_scheduler); + else + pool_of_threads_scheduler(thread_scheduler, &max_connections, + &connection_count); -static inline bool is_committing_connection(THD *thd) -{ - bool ret; + one_thread_per_connection_scheduler(extra_thread_scheduler, + &extra_max_connections, + &extra_connection_count); +#endif - mysql_mutex_lock(&thd->LOCK_wsrep_thd); - ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false; - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + global_system_variables.engine_condition_pushdown= + test(global_system_variables.optimizer_switch & + OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN); - return ret; -} + opt_readonly= read_only; -static bool have_client_connections() -{ - THD *tmp; + /* + If max_long_data_size is not specified explicitly use + value of max_allowed_packet. + */ + if (!max_long_data_size_used) + max_long_data_size= global_system_variables.max_allowed_packet; + + /* Remember if max_user_connections was 0 at startup */ + max_user_connections_checking= global_system_variables.max_user_connections != 0; - I_List_iterator it(threads); - while ((tmp=it++)) { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - if (is_client_connection(tmp) && tmp->killed == KILL_CONNECTION) + sys_var *max_relay_log_size_var, *max_binlog_size_var; + /* If max_relay_log_size is 0, then set it to max_binlog_size */ + if (!global_system_variables.max_relay_log_size) + global_system_variables.max_relay_log_size= max_binlog_size; + + /* + Fix so that DEFAULT and limit checking works with max_relay_log_size + (Yes, this is a hack, but it's required as the definition of + max_relay_log_size allows it to be set to 0). + */ + max_relay_log_size_var= intern_find_sys_var("max_relay_log_size", 0); + max_binlog_size_var= intern_find_sys_var("max_binlog_size", 0); + if (max_binlog_size_var && max_relay_log_size_var) { - (void)abort_replicated(tmp); - return true; + max_relay_log_size_var->option.min_value= + max_binlog_size_var->option.min_value; + max_relay_log_size_var->option.def_value= + max_binlog_size_var->option.def_value; } } - return false; + return 0; } + /* - returns the number of wsrep appliers running. - However, the caller (thd parameter) is not taken in account - */ -static int have_wsrep_appliers(THD *thd) -{ - int ret= 0; - THD *tmp; + Create version name for running mysqld version + We automaticly add suffixes -debug, -embedded and -log to the version + name to make the version more descriptive. + (MYSQL_SERVER_SUFFIX is set by the compilation environment) +*/ - I_List_iterator it(threads); - while ((tmp=it++)) - { - ret+= (tmp != thd && tmp->wsrep_applier); - } - return ret; +void set_server_version(void) +{ + char *end= strxmov(server_version, MYSQL_SERVER_VERSION, + MYSQL_SERVER_SUFFIX_STR, NullS); +#ifdef EMBEDDED_LIBRARY + end= strmov(end, "-embedded"); +#endif +#ifndef DBUG_OFF + if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug")) + end= strmov(end, "-debug"); +#endif + if (opt_log || opt_slow_log || opt_bin_log) + strmov(end, "-log"); // This may slow down system } -static void wsrep_close_thread(THD *thd) + +static char *get_relative_path(const char *path) { - thd->killed= KILL_CONNECTION; - MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd)); - if (thd->mysys_var) + if (test_if_hard_path(path) && + is_prefix(path,DEFAULT_MYSQL_HOME) && + strcmp(DEFAULT_MYSQL_HOME,FN_ROOTDIR)) { - thd->mysys_var->abort=1; - mysql_mutex_lock(&thd->mysys_var->mutex); - if (thd->mysys_var->current_cond) - { - mysql_mutex_lock(thd->mysys_var->current_mutex); - mysql_cond_broadcast(thd->mysys_var->current_cond); - mysql_mutex_unlock(thd->mysys_var->current_mutex); - } - mysql_mutex_unlock(&thd->mysys_var->mutex); + path+=(uint) strlen(DEFAULT_MYSQL_HOME); + while (*path == FN_LIBCHAR || *path == FN_LIBCHAR2) + path++; } + return (char*) path; } -static my_bool have_committing_connections() -{ - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - - I_List_iterator it(threads); - while ((tmp=it++)) - { - if (!is_client_connection(tmp)) - continue; - if (is_committing_connection(tmp)) - { - mysql_mutex_unlock(&LOCK_thread_count); - return TRUE; - } - } - mysql_mutex_unlock(&LOCK_thread_count); - return FALSE; -} +/** + Fix filename and replace extension where 'dir' is relative to + mysql_real_data_home. + @return + 1 if len(path) > FN_REFLEN +*/ -int wsrep_wait_committing_connections_close(int wait_time) +bool +fn_format_relative_to_data_home(char * to, const char *name, + const char *dir, const char *extension) { - int sleep_time= 100; - - while (have_committing_connections() && wait_time > 0) - { - WSREP_DEBUG("wait for committing transaction to close: %d", wait_time); - my_sleep(sleep_time); - wait_time -= sleep_time; - } - if (have_committing_connections()) + char tmp_path[FN_REFLEN]; + if (!test_if_hard_path(dir)) { - return 1; + strxnmov(tmp_path,sizeof(tmp_path)-1, mysql_real_data_home, + dir, NullS); + dir=tmp_path; } - return 0; + return !fn_format(to, name, dir, extension, + MY_APPEND_EXT | MY_UNPACK_FILENAME | MY_SAFE_PATH); } -void wsrep_close_client_connections(my_bool wait_to_end) -{ - /* - First signal all threads that it's time to die - */ - - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list - - bool kill_cached_threads_saved= kill_cached_threads; - kill_cached_threads= true; // prevent future threads caching - mysql_cond_broadcast(&COND_thread_cache); // tell cached threads to die - - I_List_iterator it(threads); - while ((tmp=it++)) - { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - /* We skip slave threads & scheduler on this first loop through. */ - if (!is_client_connection(tmp)) - continue; - - if (is_replaying_connection(tmp)) - { - tmp->killed= KILL_CONNECTION; - continue; - } - - /* replicated transactions must be skipped */ - if (abort_replicated(tmp)) - continue; - - WSREP_DEBUG("closing connection %ld", tmp->thread_id); - wsrep_close_thread(tmp); - } - mysql_mutex_unlock(&LOCK_thread_count); - if (thread_count) - sleep(2); // Give threads time to die +/** + Test a file path to determine if the path is compatible with the secure file + path restriction. + + @param path null terminated character string - mysql_mutex_lock(&LOCK_thread_count); - /* - Force remaining threads to die by closing the connection to the client - */ + @return + @retval TRUE The path is secure + @retval FALSE The path isn't secure +*/ - I_List_iterator it2(threads); - while ((tmp=it2++)) - { -#ifndef __bsdi__ // Bug in BSDI kernel - if (is_client_connection(tmp) && - !abort_replicated(tmp) && - !is_replaying_connection(tmp)) - { - WSREP_INFO("killing local connection: %ld",tmp->thread_id); - close_connection(tmp,0,0); - } -#endif - } +bool is_secure_file_path(char *path) +{ + char buff1[FN_REFLEN], buff2[FN_REFLEN]; + size_t opt_secure_file_priv_len; + /* + All paths are secure if opt_secure_file_path is 0 + */ + if (!opt_secure_file_priv) + return TRUE; - DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); - if (wsrep_debug) - WSREP_INFO("waiting for client connections to close: %u", thread_count); + opt_secure_file_priv_len= strlen(opt_secure_file_priv); - while (wait_to_end && have_client_connections()) + if (strlen(path) >= FN_REFLEN) + return FALSE; + + if (my_realpath(buff1, path, 0)) { - mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); - DBUG_PRINT("quit",("One thread died (count=%u)", thread_count)); + /* + The supplied file path might have been a file and not a directory. + */ + size_t length= dirname_length(path); // Guaranteed to be < FN_REFLEN + memcpy(buff2, path, length); + buff2[length]= '\0'; + if (length == 0 || my_realpath(buff1, buff2, 0)) + return FALSE; } - - kill_cached_threads= kill_cached_threads_saved; - - mysql_mutex_unlock(&LOCK_thread_count); - - /* All client connection threads have now been aborted */ + convert_dirname(buff2, buff1, NullS); + if (!lower_case_file_system) + { + if (strncmp(opt_secure_file_priv, buff2, opt_secure_file_priv_len)) + return FALSE; + } + else + { + if (files_charset_info->coll->strnncoll(files_charset_info, + (uchar *) buff2, strlen(buff2), + (uchar *) opt_secure_file_priv, + opt_secure_file_priv_len, + TRUE)) + return FALSE; + } + return TRUE; } -void wsrep_close_applier(THD *thd) -{ - WSREP_DEBUG("closing applier %ld", thd->thread_id); - wsrep_close_thread(thd); -} -static void wsrep_close_threads(THD *thd) +static int fix_paths(void) { - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + char buff[FN_REFLEN],*pos; + DBUG_ENTER("fix_paths"); - I_List_iterator it(threads); - while ((tmp=it++)) + convert_dirname(mysql_home,mysql_home,NullS); + /* Resolve symlinks to allow 'mysql_home' to be a relative symlink */ + my_realpath(mysql_home,mysql_home,MYF(0)); + /* Ensure that mysql_home ends in FN_LIBCHAR */ + pos=strend(mysql_home); + if (pos[-1] != FN_LIBCHAR) { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - /* We skip slave threads & scheduler on this first loop through. */ - if (tmp->wsrep_applier && tmp != thd) - { - WSREP_DEBUG("closing wsrep thread %ld", tmp->thread_id); - wsrep_close_thread (tmp); - } + pos[0]= FN_LIBCHAR; + pos[1]= 0; } + convert_dirname(lc_messages_dir, lc_messages_dir, NullS); + convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); + (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir + (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); + (void) my_load_path(pidfile_name, pidfile_name_ptr, mysql_real_data_home); - mysql_mutex_unlock(&LOCK_thread_count); -} + convert_dirname(opt_plugin_dir, opt_plugin_dir_ptr ? opt_plugin_dir_ptr : + get_relative_path(PLUGINDIR), NullS); + (void) my_load_path(opt_plugin_dir, opt_plugin_dir, mysql_home); + opt_plugin_dir_ptr= opt_plugin_dir; + pidfile_name_ptr= pidfile_name; -void wsrep_close_applier_threads(int count) -{ - THD *tmp; - mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); + mysql_unpacked_real_data_home_len= + (int) strlen(mysql_unpacked_real_data_home); + if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) + --mysql_unpacked_real_data_home_len; - I_List_iterator it(threads); - while ((tmp=it++) && count) - { - DBUG_PRINT("quit",("Informing thread %ld that it's time to die", - tmp->thread_id)); - /* We skip slave threads & scheduler on this first loop through. */ - if (tmp->wsrep_applier) - { - WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id); - tmp->wsrep_applier_closing= TRUE; - count--; - } - } + char *sharedir=get_relative_path(SHAREDIR); + if (test_if_hard_path(sharedir)) + strmake_buf(buff, sharedir); /* purecov: tested */ + else + strxnmov(buff,sizeof(buff)-1,mysql_home,sharedir,NullS); + convert_dirname(buff,buff,NullS); + (void) my_load_path(lc_messages_dir, lc_messages_dir, buff); - mysql_mutex_unlock(&LOCK_thread_count); -} + /* If --character-sets-dir isn't given, use shared library dir */ + if (charsets_dir) + strmake_buf(mysql_charsets_dir, charsets_dir); + else + strxnmov(mysql_charsets_dir, sizeof(mysql_charsets_dir)-1, buff, + CHARSET_DIR, NullS); + (void) my_load_path(mysql_charsets_dir, mysql_charsets_dir, buff); + convert_dirname(mysql_charsets_dir, mysql_charsets_dir, NullS); + charsets_dir=mysql_charsets_dir; -void wsrep_wait_appliers_close(THD *thd) -{ - /* Wait for wsrep appliers to gracefully exit */ - mysql_mutex_lock(&LOCK_thread_count); - while (have_wsrep_appliers(thd) > 1) - // 1 is for rollbacker thread which needs to be killed explicitly. - // This gotta be fixed in a more elegant manner if we gonna have arbitrary - // number of non-applier wsrep threads. + if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir)) + DBUG_RETURN(1); + if (!opt_mysql_tmpdir) + opt_mysql_tmpdir= mysql_tmpdir; +#ifdef HAVE_REPLICATION + if (!slave_load_tmpdir) + slave_load_tmpdir= mysql_tmpdir; +#endif /* HAVE_REPLICATION */ + /* + Convert the secure-file-priv option to system format, allowing + a quick strcmp to check if read or write is in an allowed dir + */ + if (opt_secure_file_priv) { - if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) + if (*opt_secure_file_priv == 0) { - mysql_mutex_unlock(&LOCK_thread_count); - my_sleep(100); - mysql_mutex_lock(&LOCK_thread_count); + my_free(opt_secure_file_priv); + opt_secure_file_priv= 0; } else - mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); - DBUG_PRINT("quit",("One applier died (count=%u)",thread_count)); - } - mysql_mutex_unlock(&LOCK_thread_count); - /* Now kill remaining wsrep threads: rollbacker */ - wsrep_close_threads (thd); - /* and wait for them to die */ - mysql_mutex_lock(&LOCK_thread_count); - while (have_wsrep_appliers(thd) > 0) - { - if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION) { - mysql_mutex_unlock(&LOCK_thread_count); - my_sleep(100); - mysql_mutex_lock(&LOCK_thread_count); + if (strlen(opt_secure_file_priv) >= FN_REFLEN) + opt_secure_file_priv[FN_REFLEN-1]= '\0'; + if (my_realpath(buff, opt_secure_file_priv, 0)) + { + sql_print_warning("Failed to normalize the argument for --secure-file-priv."); + DBUG_RETURN(1); + } + char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE)); + convert_dirname(secure_file_real_path, buff, NullS); + my_free(opt_secure_file_priv); + opt_secure_file_priv= secure_file_real_path; } - else - mysql_cond_wait(&COND_thread_count,&LOCK_thread_count); - DBUG_PRINT("quit",("One thread died (count=%u)",thread_count)); } - mysql_mutex_unlock(&LOCK_thread_count); + DBUG_RETURN(0); +} - /* All wsrep applier threads have now been aborted. However, if this thread - is also applier, we are still running... - */ +/** + Check if file system used for databases is case insensitive. + + @param dir_name Directory to test + + @retval -1 Don't know (Test failed) + @retval 0 File system is case sensitive + @retval 1 File system is case insensitive +*/ + +static int test_if_case_insensitive(const char *dir_name) +{ + int result= 0; + File file; + char buff[FN_REFLEN], buff2[FN_REFLEN]; + MY_STAT stat_info; + DBUG_ENTER("test_if_case_insensitive"); + + fn_format(buff, glob_hostname, dir_name, ".lower-test", + MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); + fn_format(buff2, glob_hostname, dir_name, ".LOWER-TEST", + MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); + mysql_file_delete(key_file_casetest, buff2, MYF(0)); + if ((file= mysql_file_create(key_file_casetest, + buff, 0666, O_RDWR, MYF(0))) < 0) + { + if (!opt_abort) + sql_print_warning("Can't create test file %s", buff); + DBUG_RETURN(-1); + } + mysql_file_close(file, MYF(0)); + if (mysql_file_stat(key_file_casetest, buff2, &stat_info, MYF(0))) + result= 1; // Can access file + mysql_file_delete(key_file_casetest, buff, MYF(MY_WME)); + DBUG_PRINT("exit", ("result: %d", result)); + DBUG_RETURN(result); } +#ifndef EMBEDDED_LIBRARY -void wsrep_kill_mysql(THD *thd) +/** + Create file to store pid number. +*/ +static void create_pid_file() { - if (mysqld_server_started) + File file; + if ((file= mysql_file_create(key_file_pid, pidfile_name, 0664, + O_WRONLY | O_TRUNC, MYF(MY_WME))) >= 0) { - if (!shutdown_in_progress) + char buff[MAX_BIGINT_WIDTH + 1], *end; + end= int10_to_str((long) getpid(), buff, 10); + *end++= '\n'; + if (!mysql_file_write(file, (uchar*) buff, (uint) (end-buff), + MYF(MY_WME | MY_NABP))) { - WSREP_INFO("starting shutdown"); - kill_mysql(); + mysql_file_close(file, MYF(0)); + pid_file_created= true; + return; } + mysql_file_close(file, MYF(0)); } - else - { - unireg_abort(1); - } + sql_perror("Can't start server: can't create PID file"); + exit(1); } -#endif /* WITH_WSREP */ +#endif /* EMBEDDED_LIBRARY */ + /** Remove the process' pid file. diff --git a/sql/slave.cc b/sql/slave.cc index 1d87e16249a..8665cf646fc 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3118,23 +3118,6 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli) ev->thd = thd; // because up to this point, ev->thd == 0 int reason= ev->shall_skip(rli); -#ifdef WITH_WSREP - if (WSREP_ON && (ev->get_type_code() == XID_EVENT || - (ev->get_type_code() == QUERY_EVENT && thd->wsrep_mysql_replicated > 0 && - (!strncasecmp(((Query_log_event*)ev)->query , "BEGIN", 5) || - !strncasecmp(((Query_log_event*)ev)->query , "COMMIT", 6) )))) - { - if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) - { - WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated); - reason = Log_event::EVENT_SKIP_IGNORE; - } - else - { - thd->wsrep_mysql_replicated = 0; - } - } -#endif if (reason == Log_event::EVENT_SKIP_COUNT) { DBUG_ASSERT(rli->slave_skip_counter > 0); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1ededf0dd61..325c79043a3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4429,6 +4429,15 @@ restart: #endif err: +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "exit open_tables()"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ + free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block if (error && *table_to_open) @@ -4881,6 +4890,16 @@ end: trans_rollback_stmt(thd); close_thread_tables(thd); } + +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "End opening table"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ + DBUG_RETURN(table); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d2bc3328643..ef139dfefeb 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3187,6 +3187,12 @@ bool Delayed_insert::handle_inserts(void) mysql_cond_broadcast(&cond_client); // If waiting clients } } +#ifdef WITH_WSREP + if (WSREP((&thd))) + thd_proc_info(&thd, "insert done"); + else +#endif /* WITH_WSREP */ + thd_proc_info(&thd, 0); mysql_mutex_unlock(&mutex); /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7239c99613c..675e82de145 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -970,9 +970,12 @@ bool do_command(THD *thd) thd->wsrep_query_state= QUERY_EXEC; mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } -#endif /* WITH_WSREP */ + if ((WSREP(thd) && packet_length == packet_error) || + (!WSREP(thd) && (packet_length= my_net_read(net)) == packet_error)) +#else if (packet_length == packet_error) +#endif /* WITH_WSREP */ { DBUG_PRINT("info",("Got error %d reading command from socket %s", net->error, @@ -2708,9 +2711,6 @@ mysql_execute_command(THD *thd) my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server"); break; #endif -#ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; -#endif /* WITH_WSREP */ case SQLCOM_SHOW_STATUS: { execute_show_status(thd, all_tables); @@ -2745,6 +2745,10 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: +#ifdef WITH_WSREP + if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error; +#endif /* WITH_WSREP */ + case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TRIGGERS: @@ -3237,12 +3241,6 @@ case SQLCOM_PREPARE: if (create_info.tmp_table()) thd->variables.option_bits|= OPTION_KEEP_LOG; /* regular create */ -#ifdef WITH_WSREP - if (!thd->is_current_stmt_binlog_format_row() || - !(create_info.options & HA_LEX_CREATE_TMP_TABLE)) - WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, - NULL) -#endif /* WITH_WSREP */ if (create_info.options & HA_LEX_CREATE_TABLE_LIKE) { /* CREATE TABLE ... LIKE ... */ @@ -3251,6 +3249,13 @@ case SQLCOM_PREPARE: } else { +#ifdef WITH_WSREP + if (!thd->is_current_stmt_binlog_format_row() || + !(create_info.options & HA_LEX_CREATE_TMP_TABLE)) + WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name, + NULL) +#endif /* WITH_WSREP */ + /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, &create_info, &alter_info); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 5a93f3b819a..412b941e946 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2815,6 +2815,15 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) err: unlock_slave_threads(mi); +#ifdef WITH_WSREP + if (WSREP(thd)) + thd_proc_info(thd, "exit stop_slave()"); + else + thd_proc_info(thd, 0); +#else /* WITH_WSREP */ + thd_proc_info(thd, 0); +#endif /* WITH_WSREP */ + if (slave_errno) { if (net_report) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 46f23838850..d63df895a13 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -59,6 +59,10 @@ #include "debug_sync.h" #include "keycaches.h" +#if !defined(MYSQL_MAX_VARIABLE_VALUE_LEN) +#define MYSQL_MAX_VARIABLE_VALUE_LEN 1024 +#endif // !defined(MYSQL_MAX_VARIABLE_VALUE_LEN) + #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" #endif @@ -8660,7 +8664,7 @@ ST_FIELD_INFO variables_fields_info[]= { {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name", SKIP_OPEN_TABLE}, - {"VARIABLE_VALUE", 1024, MYSQL_TYPE_STRING, 0, 1, + {"VARIABLE_VALUE", MYSQL_MAX_VARIABLE_VALUE_LEN, MYSQL_TYPE_STRING, 0, 1, "Value", SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} };