1 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; version 2 of the License.
6 
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11 
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
15 
16 /*
17  * sql_manager.cc
18  * This thread manages various maintenance tasks.
19  *
20  *   o Flushing the tables every flush_time seconds.
21  *   o Berkeley DB: removing unneeded log files.
22  */
23 
24 #include "mariadb.h"
25 #include "sql_priv.h"
26 #include "sql_manager.h"
27 #include "sql_base.h"                           // flush_tables
28 
29 static bool volatile manager_thread_in_use = 0;
30 static bool abort_manager = false;
31 
32 pthread_t manager_thread;
33 mysql_mutex_t LOCK_manager;
34 mysql_cond_t COND_manager;
35 
36 struct handler_cb {
37    struct handler_cb *next;
38    void (*action)(void *);
39    void *data;
40 };
41 
42 static struct handler_cb *cb_list; // protected by LOCK_manager
43 
mysql_manager_submit(void (* action)(void *),void * data)44 bool mysql_manager_submit(void (*action)(void *), void *data)
45 {
46   bool result= FALSE;
47   DBUG_ASSERT(manager_thread_in_use);
48   struct handler_cb **cb;
49   mysql_mutex_lock(&LOCK_manager);
50   cb= &cb_list;
51   while (*cb)
52     cb= &(*cb)->next;
53   *cb= (struct handler_cb *)my_malloc(sizeof(struct handler_cb), MYF(MY_WME));
54   if (!*cb)
55     result= TRUE;
56   else
57   {
58     (*cb)->next= NULL;
59     (*cb)->action= action;
60     (*cb)->data= data;
61   }
62   mysql_cond_signal(&COND_manager);
63   mysql_mutex_unlock(&LOCK_manager);
64   return result;
65 }
66 
handle_manager(void * arg)67 pthread_handler_t handle_manager(void *arg __attribute__((unused)))
68 {
69   int error = 0;
70   struct timespec abstime;
71   bool reset_flush_time = TRUE;
72   my_thread_init();
73   DBUG_ENTER("handle_manager");
74 
75   pthread_detach_this_thread();
76   manager_thread = pthread_self();
77   mysql_mutex_lock(&LOCK_manager);
78   while (!abort_manager)
79   {
80     /* XXX: This will need to be made more general to handle different
81      * polling needs. */
82     if (flush_time)
83     {
84       if (reset_flush_time)
85       {
86 	set_timespec(abstime, flush_time);
87         reset_flush_time = FALSE;
88       }
89       while ((!error || error == EINTR) && !abort_manager && !cb_list)
90         error= mysql_cond_timedwait(&COND_manager, &LOCK_manager, &abstime);
91 
92       if (error == ETIMEDOUT || error == ETIME)
93       {
94         tc_purge();
95         error = 0;
96         reset_flush_time = TRUE;
97       }
98     }
99     else
100     {
101       while ((!error || error == EINTR) && !abort_manager && !cb_list)
102         error= mysql_cond_wait(&COND_manager, &LOCK_manager);
103     }
104 
105     struct handler_cb *cb= cb_list;
106     cb_list= NULL;
107     mysql_mutex_unlock(&LOCK_manager);
108 
109     while (cb)
110     {
111       struct handler_cb *next= cb->next;
112       cb->action(cb->data);
113       my_free(cb);
114       cb= next;
115     }
116     mysql_mutex_lock(&LOCK_manager);
117   }
118   manager_thread_in_use = 0;
119   mysql_mutex_unlock(&LOCK_manager);
120   mysql_mutex_destroy(&LOCK_manager);
121   mysql_cond_destroy(&COND_manager);
122   DBUG_LEAVE; // Can't use DBUG_RETURN after my_thread_end
123   my_thread_end();
124   return (NULL);
125 }
126 
127 
128 /* Start handle manager thread */
start_handle_manager()129 void start_handle_manager()
130 {
131   DBUG_ENTER("start_handle_manager");
132   abort_manager = false;
133   {
134     pthread_t hThread;
135     int err;
136     manager_thread_in_use = 1;
137     mysql_cond_init(key_COND_manager, &COND_manager,NULL);
138     mysql_mutex_init(key_LOCK_manager, &LOCK_manager, NULL);
139     if ((err= mysql_thread_create(key_thread_handle_manager, &hThread,
140                                   &connection_attrib, handle_manager, 0)))
141       sql_print_warning("Can't create handle_manager thread (errno: %M)", err);
142   }
143   DBUG_VOID_RETURN;
144 }
145 
146 
147 /* Initiate shutdown of handle manager thread */
stop_handle_manager()148 void stop_handle_manager()
149 {
150   DBUG_ENTER("stop_handle_manager");
151   if (manager_thread_in_use)
152   {
153     mysql_mutex_lock(&LOCK_manager);
154     abort_manager = true;
155     DBUG_PRINT("quit", ("initiate shutdown of handle manager thread: %lu",
156                         (ulong)manager_thread));
157     mysql_cond_signal(&COND_manager);
158     mysql_mutex_unlock(&LOCK_manager);
159   }
160   DBUG_VOID_RETURN;
161 }
162 
163