]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/wait.c
- Correct typo in Copyright
[bacula/bacula] / bacula / src / stored / wait.c
1 /*
2  *  Subroutines to handle waiting for operator intervention
3  *   or waiting for a Device to be released
4  *
5  *  Code for wait_for_sysop() pulled from askdir.c
6  *
7  *   Kern Sibbald, March 2005
8  *
9  *   Version $Id$
10  */
11 /*
12    Copyright (C) 2000-2005 Kern Sibbald
13
14    This program is free software; you can redistribute it and/or
15    modify it under the terms of the GNU General Public License
16    version 2 as amended with additional clauses defined in the
17    file LICENSE in the main source directory.
18
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
22    the file LICENSE for additional details.
23
24  */
25
26 #include "bacula.h"                   /* pull in global headers */
27 #include "stored.h"                   /* pull in Storage Deamon headers */
28
29 static bool double_jcr_wait_time(JCR *jcr);
30
31
32 /*
33  * Wait for SysOp to mount a tape on a specific device
34  *
35  *   Returns: status from pthread_cond_timedwait() 
36  */
37 int wait_for_sysop(DCR *dcr)
38 {
39    struct timeval tv;
40    struct timezone tz;
41    struct timespec timeout;
42    time_t last_heartbeat = 0;
43    time_t first_start = time(NULL);
44    int stat = 0;
45    int add_wait;
46    bool unmounted;
47    DEVICE *dev = dcr->dev;
48    JCR *jcr = dcr->jcr;
49
50    P(dev->mutex);
51    Dmsg1(100, "Enter blocked=%s\n", dev->print_blocked());
52    unmounted = is_device_unmounted(dev);
53
54    dev->poll = false;
55    /*
56     * Wait requested time (dev->rem_wait_sec).  However, we also wake up every
57     *    HB_TIME seconds and send a heartbeat to the FD and the Director
58     *    to keep stateful firewalls from closing them down while waiting
59     *    for the operator.
60     */
61    add_wait = dev->rem_wait_sec;
62    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
63       add_wait = me->heartbeat_interval;
64    }
65    /* If the user did not unmount the tape and we are polling, ensure
66     *  that we poll at the correct interval.
67     */
68    if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
69       add_wait = dev->vol_poll_interval;
70    }
71
72    if (!unmounted) {
73       Dmsg1(400, "blocked=%s\n", dev->print_blocked());
74       dev->dev_prev_blocked = dev->dev_blocked;
75       dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
76    }
77
78    for ( ; !job_canceled(jcr); ) {
79       time_t now, start;
80
81       gettimeofday(&tv, &tz);
82       timeout.tv_nsec = tv.tv_usec * 1000;
83       timeout.tv_sec = tv.tv_sec + add_wait;
84
85       Dmsg3(400, "I'm going to sleep on device %s. HB=%d wait=%d\n", dev->print_name(),
86          (int)me->heartbeat_interval, dev->wait_sec);
87       start = time(NULL);
88       /* Wait required time */
89       stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
90       Dmsg2(400, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
91          dev->print_blocked());
92
93       now = time(NULL);
94       dev->rem_wait_sec -= (now - start);
95
96       /* Note, this always triggers the first time. We want that. */
97       if (me->heartbeat_interval) {
98          if (now - last_heartbeat >= me->heartbeat_interval) {
99             /* send heartbeats */
100             if (jcr->file_bsock) {
101                bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
102                Dmsg0(400, "Send heartbeat to FD.\n");
103             }
104             if (jcr->dir_bsock) {
105                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
106             }
107             last_heartbeat = now;
108          }
109       }
110
111       /*
112        * Check if user unmounted the device while we were waiting
113        */
114       unmounted = is_device_unmounted(dev);
115
116       if (stat != ETIMEDOUT) {     /* we blocked the device */
117          break;                    /* on error return */
118       }
119       if (dev->rem_wait_sec <= 0) {  /* on exceeding wait time return */
120          Dmsg0(400, "Exceed wait time.\n");
121          break;
122       }
123
124       if (!unmounted && dev->vol_poll_interval &&
125           (now - first_start >= dev->vol_poll_interval)) {
126          Dmsg1(400, "In wait blocked=%s\n", dev->print_blocked());
127          dev->poll = true;            /* returning a poll event */
128          break;
129       }
130       /*
131        * Check if user mounted the device while we were waiting
132        */
133       if (dev->get_blocked() == BST_MOUNT) {   /* mount request ? */
134          stat = 0;
135          break;
136       }
137
138       add_wait = dev->wait_sec - (now - start);
139       if (add_wait < 0) {
140          add_wait = 0;
141       }
142       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
143          add_wait = me->heartbeat_interval;
144       }
145    }
146
147    if (!unmounted) {
148       dev->set_blocked(dev->dev_prev_blocked);    /* restore entry state */
149       Dmsg1(400, "set %s\n", dev->print_blocked());
150    }
151    Dmsg1(400, "Exit blocked=%s\n", dev->print_blocked());
152    V(dev->mutex);
153    return stat;
154 }
155
156
157 /*
158  * Wait for any device to be released, then we return, so 
159  *  higher level code can rescan possible devices.
160  * 
161  * Returns: true  if a device has changed state
162  *          false if the total wait time has expired.
163  */
164 bool wait_for_device(JCR *jcr, bool first)
165 {
166    struct timeval tv;
167    struct timezone tz;
168    struct timespec timeout;
169 // time_t last_heartbeat = 0;
170    int stat = 0;
171    int add_wait;
172    bool ok = false;
173
174    Dmsg0(100, "Enter wait_for_device\n");
175    P(device_release_mutex);
176
177    if (first) {
178       Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to reserve a device.\n"), jcr->Job);
179    }
180
181    /*
182     * Wait requested time (dev->rem_wait_sec).  However, we also wake up every
183     *    HB_TIME seconds and send a heartbeat to the FD and the Director
184     *    to keep stateful firewalls from closing them down while waiting
185     *    for the operator.
186     */
187    add_wait = jcr->rem_wait_sec;
188    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
189       add_wait = me->heartbeat_interval;
190    }
191
192    for ( ; !job_canceled(jcr); ) {
193       time_t now, start;
194
195       gettimeofday(&tv, &tz);
196       timeout.tv_nsec = tv.tv_usec * 1000;
197       timeout.tv_sec = tv.tv_sec + add_wait;
198
199       Dmsg3(100, "I'm going to wait for a device. HB=%d wait=%d remwait=%d\n", 
200          (int)me->heartbeat_interval, jcr->wait_sec, jcr->rem_wait_sec);
201       start = time(NULL);
202       /* Wait required time */
203       stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
204       Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat);
205
206       now = time(NULL);
207       jcr->rem_wait_sec -= (now - start);
208
209 #ifdef needed
210       /* Note, this always triggers the first time. We want that. */
211       if (me->heartbeat_interval) {
212          if (now - last_heartbeat >= me->heartbeat_interval) {
213             /* send heartbeats */
214             if (jcr->file_bsock) {
215                bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
216                Dmsg0(400, "Send heartbeat to FD.\n");
217             }
218             if (jcr->dir_bsock) {
219                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
220             }
221             last_heartbeat = now;
222          }
223       }
224 #endif
225
226       if (stat != ETIMEDOUT) {     /* if someone woke us up */
227          ok = true;
228          break;                    /* allow caller to examine device */
229       }
230       if (jcr->rem_wait_sec <= 0) {  /* on exceeding wait time return */
231          Dmsg0(400, "Exceed wait time.\n");
232          if (!double_jcr_wait_time(jcr)) {
233             break;                 /* give up */
234          }
235          Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to reserve a device.\n"), jcr->Job);
236       }
237
238       add_wait = jcr->wait_sec - (now - start);
239       if (add_wait < 0) {
240          add_wait = 0;
241       }
242       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
243          add_wait = me->heartbeat_interval;
244       }
245    }
246
247    V(device_release_mutex);
248    Dmsg1(100, "Return from wait_device ok=%d\n", ok);
249    return ok;
250 }
251
252 /*
253  * The jcr timers are used for waiting on any device *
254  * Returns: true if time doubled
255  *          false if max time expired
256  */
257 static bool double_jcr_wait_time(JCR *jcr)
258 {
259    jcr->wait_sec *= 2;               /* double wait time */
260    if (jcr->wait_sec > jcr->max_wait) {   /* but not longer than maxtime */
261       jcr->wait_sec = jcr->max_wait;
262    }
263    jcr->num_wait++;
264    jcr->rem_wait_sec = jcr->wait_sec;
265    if (jcr->num_wait >= jcr->max_num_wait) {
266       return false;
267    }
268    return true;
269 }