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