]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/heartbeat.c
b83eef9cadea8006e596839ec20b784c2e3cbb36
[bacula/bacula] / bacula / src / filed / heartbeat.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2003-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *  Bacula File Daemon heartbeat routines
18  *    Listens for heartbeats coming from the SD
19  *    If configured, sends heartbeats to Dir
20  *
21  *    Kern Sibbald, May MMIII
22  *
23  */
24
25 #include "bacula.h"
26 #include "filed.h"
27
28 #define WAIT_INTERVAL 5
29
30 extern "C" void *sd_heartbeat_thread(void *arg);
31 extern "C" void *dir_heartbeat_thread(void *arg);
32 extern bool no_signals;
33
34 /*
35  * Listen on the SD socket for heartbeat signals.
36  * Send heartbeats to the Director every HB_TIME
37  *   seconds.
38  */
39 extern "C" void *sd_heartbeat_thread(void *arg)
40 {
41    int32_t n;
42    JCR *jcr = (JCR *)arg;
43    BSOCK *sd, *dir;
44    time_t last_heartbeat = time(NULL);
45    time_t now;
46
47    pthread_detach(pthread_self());
48
49    /* Get our own local copy */
50    sd = dup_bsock(jcr->store_bsock);
51    dir = dup_bsock(jcr->dir_bsock);
52
53    jcr->hb_bsock = sd;
54    jcr->hb_started = true;
55    jcr->hb_dir_bsock = dir;
56    dir->suppress_error_messages(true);
57    sd->suppress_error_messages(true);
58
59    /* Hang reading the socket to the SD, and every time we get
60     *   a heartbeat or we get a wait timeout (5 seconds), we
61     *   check to see if we need to send a heartbeat to the
62     *   Director.
63     */
64    while (!sd->is_stop()) {
65       n = sd->wait_data_intr(WAIT_INTERVAL);
66       if (n < 0 || sd->is_stop()) {
67          break;
68       }
69       if (me->heartbeat_interval) {
70          now = time(NULL);
71          if (now-last_heartbeat >= me->heartbeat_interval) {
72             dir->signal(BNET_HEARTBEAT);
73             if (dir->is_stop()) {
74                break;
75             }
76             last_heartbeat = now;
77          }
78       }
79       if (n == 1) {               /* input waiting */
80          sd->recv();              /* read it -- probably heartbeat from sd */
81          if (sd->is_stop()) {
82             break;
83          }
84          if (sd->msglen <= 0) {
85             Dmsg1(100, "Got BNET_SIG %d from SD\n", sd->msglen);
86          } else {
87             Dmsg2(100, "Got %d bytes from SD. MSG=%s\n", sd->msglen, sd->msg);
88          }
89       }
90       Dmsg2(200, "wait_intr=%d stop=%d\n", n, sd->is_stop());
91    }
92    /*
93     * Note, since sd and dir are local dupped sockets, this
94     *  is one place where we can call destroy().
95     */
96    sd->destroy();
97    dir->destroy();
98    jcr->hb_bsock = NULL;
99    jcr->hb_started = false;
100    jcr->hb_dir_bsock = NULL;
101    return NULL;
102 }
103
104 /* Startup the heartbeat thread -- see above */
105 void start_heartbeat_monitor(JCR *jcr)
106 {
107    /*
108     * If no signals are set, do not start the heartbeat because
109     * it gives a constant stream of TIMEOUT_SIGNAL signals that
110     * make debugging impossible.
111     */
112    if (!no_signals) {
113       jcr->hb_bsock = NULL;
114       jcr->hb_started = false;
115       jcr->hb_dir_bsock = NULL;
116       pthread_create(&jcr->heartbeat_id, NULL, sd_heartbeat_thread, (void *)jcr);
117    }
118 }
119
120 /* Terminate the heartbeat thread. Used for both SD and DIR */
121 void stop_heartbeat_monitor(JCR *jcr)
122 {
123    int cnt = 0;
124    if (no_signals) {
125       return;
126    }
127    /* Wait max 10 secs for heartbeat thread to start */
128    while (!jcr->hb_started && cnt++ < 200) {
129       bmicrosleep(0, 50000);         /* wait for start */
130    }
131
132    if (jcr->hb_started) {
133       jcr->hb_bsock->set_timed_out();       /* set timed_out to terminate read */
134       jcr->hb_bsock->set_terminated();      /* set to terminate read */
135    }
136    if (jcr->hb_dir_bsock) {
137       jcr->hb_dir_bsock->set_timed_out();     /* set timed_out to terminate read */
138       jcr->hb_dir_bsock->set_terminated();    /* set to terminate read */
139    }
140    if (jcr->hb_started) {
141       Dmsg0(100, "Send kill to heartbeat id\n");
142       pthread_kill(jcr->heartbeat_id, TIMEOUT_SIGNAL);  /* make heartbeat thread go away */
143       bmicrosleep(0, 50000);
144    }
145    cnt = 0;
146    /* Wait max 100 secs for heartbeat thread to stop */
147    while (jcr->hb_started && cnt++ < 200) {
148       pthread_kill(jcr->heartbeat_id, TIMEOUT_SIGNAL);  /* make heartbeat thread go away */
149       bmicrosleep(0, 500000);
150    }
151 }
152
153 /*
154  * Thread for sending heartbeats to the Director when there
155  *   is no SD monitoring needed -- e.g. restore and verify Vol
156  *   both do their own read() on the SD socket.
157  */
158 extern "C" void *dir_heartbeat_thread(void *arg)
159 {
160    JCR *jcr = (JCR *)arg;
161    BSOCK *dir;
162    time_t last_heartbeat = time(NULL);
163
164    pthread_detach(pthread_self());
165
166    /* Get our own local copy */
167    dir = dup_bsock(jcr->dir_bsock);
168
169    jcr->hb_bsock = dir;
170    jcr->hb_started = true;
171    dir->suppress_error_messages(true);
172
173    while (!dir->is_stop()) {
174       time_t now, next;
175
176       now = time(NULL);
177       next = now - last_heartbeat;
178       if (next >= me->heartbeat_interval) {
179          dir->signal(BNET_HEARTBEAT);
180          if (dir->is_stop()) {
181             break;
182          }
183          last_heartbeat = now;
184       }
185       bmicrosleep(next, 0);
186    }
187    dir->destroy();
188    jcr->hb_bsock = NULL;
189    jcr->hb_started = false;
190    return NULL;
191 }
192
193 /*
194  * Same as above but we don't listen to the SD
195  */
196 void start_dir_heartbeat(JCR *jcr)
197 {
198    if (me->heartbeat_interval) {
199       jcr->dir_bsock->set_locking();
200       pthread_create(&jcr->heartbeat_id, NULL, dir_heartbeat_thread, (void *)jcr);
201    }
202 }
203
204 void stop_dir_heartbeat(JCR *jcr)
205 {
206    if (me->heartbeat_interval) {
207       stop_heartbeat_monitor(jcr);
208    }
209 }