@@ -535,26 +535,27 @@ void free_global_client_stats(void)
535
535
my_hash_free (&global_client_stats);
536
536
}
537
537
538
+
538
539
/*
539
- Increments the global stats connection count for an entry from
540
- global_client_stats or global_user_stats. Returns 0 on success
541
- and 1 on error.
542
- */
540
+ Common code for increment_count_by_name, decrement_count_by_name, to fetch
541
+ the USER_STATS corresponding to 'name'.
542
+ */
543
543
544
- static bool increment_count_by_name (const char *name, size_t name_length,
545
- const char *role_name,
546
- HASH *users_or_clients, THD *thd)
544
+ static USER_STATS* count_by_name_common (const char *name, size_t name_length,
545
+ const char *role_name,
546
+ HASH *users_or_clients, THD *thd)
547
547
{
548
- USER_STATS *user_stats;
548
+ USER_STATS *user_stats= nullptr ;
549
549
550
- if (!(user_stats= (USER_STATS*) my_hash_search (users_or_clients, (uchar*) name,
551
- name_length)))
550
+ if (!(user_stats= (USER_STATS*) my_hash_search (users_or_clients,
551
+ (uchar*) name,
552
+ name_length)))
552
553
{
553
554
/* First connection for this user or client */
554
555
if (!(user_stats= ((USER_STATS*)
555
556
my_malloc (PSI_INSTRUMENT_ME, sizeof (USER_STATS),
556
557
MYF (MY_WME | MY_ZEROFILL)))))
557
- return TRUE ; // Out of memory
558
+ return nullptr ; // Out of memory
558
559
559
560
init_user_stats (user_stats, name, name_length, role_name,
560
561
0 , 0 , 0 , // connections
@@ -573,12 +574,68 @@ static bool increment_count_by_name(const char *name, size_t name_length,
573
574
if (my_hash_insert (users_or_clients, (uchar*)user_stats))
574
575
{
575
576
my_free (user_stats);
576
- return TRUE ; // Out of memory
577
+ return nullptr ; // Out of memory
577
578
}
578
579
}
579
- user_stats->total_connections ++;
580
+
581
+ DBUG_ASSERT (user_stats);
582
+ return user_stats;
583
+ }
584
+
585
+
586
+ /*
587
+ Increments the global stats connection count for an entry from
588
+ global_client_stats or global_user_stats. Returns FALSE on success
589
+ and TRUE on error.
590
+ */
591
+
592
+ static bool increment_count_by_name (const char *name, size_t name_length,
593
+ const char *role_name,
594
+ HASH *users_or_clients, THD *thd)
595
+ {
596
+ USER_STATS *user_stats= count_by_name_common (name, name_length, role_name,
597
+ users_or_clients, thd);
598
+ if (!user_stats)
599
+ return TRUE ;
600
+
601
+ ++user_stats->total_connections ;
602
+ #ifndef EMBEDDED_LIBRARY
603
+ /*
604
+ For the embedded library, we get here only because THD::update_all_stats
605
+ is called after command dispatch, not because of any connection events
606
+ (those are compiled-out for the embedded library). Maybe this entire
607
+ function should do nothing in the case of embedded library? At least
608
+ this makes it behave the same way it did before supporting
609
+ concurrent_connections.
610
+ */
611
+ ++user_stats->concurrent_connections ;
612
+ #endif
580
613
if (thd->net .vio && thd->net .vio ->type == VIO_TYPE_SSL)
581
- user_stats->total_ssl_connections ++;
614
+ ++user_stats->total_ssl_connections ;
615
+
616
+ return FALSE ;
617
+ }
618
+
619
+
620
+ /*
621
+ Decrements the global stats connection count for an entry from
622
+ global_client_stats or global_user_stats. Returns FALSE on success
623
+ and TRUE on error.
624
+ */
625
+
626
+ #ifndef EMBEDDED_LIBRARY
627
+ static bool decrement_count_by_name (const char *name, size_t name_length,
628
+ const char *role_name,
629
+ HASH *users_or_clients, THD *thd)
630
+ {
631
+ USER_STATS *user_stats= count_by_name_common (name, name_length, role_name,
632
+ users_or_clients, thd);
633
+ if (!user_stats)
634
+ return TRUE ;
635
+
636
+ if (user_stats->concurrent_connections > 0 )
637
+ --user_stats->concurrent_connections ;
638
+
582
639
return FALSE ;
583
640
}
584
641
@@ -592,36 +649,65 @@ static bool increment_count_by_name(const char *name, size_t name_length,
592
649
@retval 1 error.
593
650
*/
594
651
595
- #ifndef EMBEDDED_LIBRARY
596
- static bool increment_connection_count (THD* thd, bool use_lock)
652
+ static bool increment_connection_count (THD* thd)
597
653
{
598
654
const char *user_string= get_valid_user_string (thd->main_security_ctx .user );
599
655
const char *client_string= get_client_host (thd);
600
- bool return_value= FALSE ;
601
656
602
657
if (!thd->userstat_running )
603
658
return FALSE ;
604
659
605
- if (use_lock)
606
- mysql_mutex_lock (&LOCK_global_user_client_stats);
660
+ mysql_mutex_lock (&LOCK_global_user_client_stats);
661
+ SCOPE_EXIT ([] () {
662
+ mysql_mutex_unlock (&LOCK_global_user_client_stats);
663
+ });
607
664
608
665
if (increment_count_by_name (user_string, strlen (user_string), user_string,
609
666
&global_user_stats, thd))
610
- {
611
- return_value= TRUE ;
612
- goto end;
613
- }
667
+ return TRUE ;
668
+
614
669
if (increment_count_by_name (client_string, strlen (client_string),
615
670
user_string, &global_client_stats, thd))
616
- {
617
- return_value= TRUE ;
618
- goto end;
619
- }
671
+ return TRUE ;
620
672
621
- end:
622
- if (use_lock)
673
+ return FALSE ;
674
+ }
675
+
676
+ static bool decrement_connection_count (THD* thd)
677
+ {
678
+ const char *user_string= get_valid_user_string (thd->main_security_ctx .user );
679
+ const char *client_string= get_client_host (thd);
680
+
681
+ /*
682
+ THD::update_all_stats, called only from dispatch_command, clears
683
+ thd->userstat_running to avoid double counting. thd->userstat_running
684
+ is set during THD::init.
685
+
686
+ When a user connects for the first time, thd->userstat_running is set
687
+ from the global variable opt_userstat_running during THD::init (indirectly
688
+ called from THD::change_user). After each dispatched command, as noted
689
+ above, it is cleared (even if the user maintains the connection). So for
690
+ normal cases where the user disconnects after running a query, we need to
691
+ check opt_userstat_running. We check thd->userstat_running for abnormal
692
+ cases where the user disconnects during a dispatched command, before it
693
+ reaches THD::update_all_stats.
694
+ */
695
+ if (!thd->userstat_running && !opt_userstat_running)
696
+ return FALSE ;
697
+
698
+ mysql_mutex_lock (&LOCK_global_user_client_stats);
699
+ SCOPE_EXIT ([] () {
623
700
mysql_mutex_unlock (&LOCK_global_user_client_stats);
624
- return return_value;
701
+ });
702
+
703
+ if (decrement_count_by_name (user_string, strlen (user_string), user_string,
704
+ &global_user_stats, thd))
705
+ return TRUE ;
706
+ if (decrement_count_by_name (client_string, strlen (client_string),
707
+ user_string, &global_client_stats, thd))
708
+ return TRUE ;
709
+
710
+ return FALSE ;
625
711
}
626
712
#endif
627
713
@@ -1143,7 +1229,7 @@ bool login_connection(THD *thd)
1143
1229
my_net_set_write_timeout (net, thd->variables .net_write_timeout );
1144
1230
1145
1231
/* Updates global user connection stats. */
1146
- if (increment_connection_count (thd, TRUE ))
1232
+ if (increment_connection_count (thd))
1147
1233
{
1148
1234
my_error (ER_OUTOFMEMORY, MYF (0 ), (int ) (2 *sizeof (USER_STATS)));
1149
1235
error= 1 ;
@@ -1202,6 +1288,9 @@ void end_connection(THD *thd)
1202
1288
if (likely (!thd->killed ) && (net->error && net->vio != 0 ))
1203
1289
thd->print_aborted_warning (1 , thd->get_stmt_da ()->is_error ()
1204
1290
? thd->get_stmt_da ()->message () : ER_THD (thd, ER_UNKNOWN_ERROR));
1291
+
1292
+ if (decrement_connection_count (thd))
1293
+ my_error (ER_OUTOFMEMORY, MYF (ME_ERROR_LOG), (int ) (2 *sizeof (USER_STATS)));
1205
1294
}
1206
1295
1207
1296
0 commit comments