]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/wait.c
Minor changes
[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 ammended 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    unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
52                 (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
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       dev->dev_prev_blocked = dev->dev_blocked;
74       dev->dev_blocked = BST_WAITING_FOR_SYSOP; /* indicate waiting for mount */
75    }
76
77    for ( ; !job_canceled(jcr); ) {
78       time_t now, start;
79
80       gettimeofday(&tv, &tz);
81       timeout.tv_nsec = tv.tv_usec * 1000;
82       timeout.tv_sec = tv.tv_sec + add_wait;
83
84       Dmsg3(400, "I'm going to sleep on device %s. HB=%d wait=%d\n", dev->print_name(),
85          (int)me->heartbeat_interval, dev->wait_sec);
86       start = time(NULL);
87       /* Wait required time */
88       stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
89       Dmsg1(400, "Wokeup from sleep on device stat=%d\n", stat);
90
91       now = time(NULL);
92       dev->rem_wait_sec -= (now - start);
93
94       /* Note, this always triggers the first time. We want that. */
95       if (me->heartbeat_interval) {
96          if (now - last_heartbeat >= me->heartbeat_interval) {
97             /* send heartbeats */
98             if (jcr->file_bsock) {
99                bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
100                Dmsg0(400, "Send heartbeat to FD.\n");
101             }
102             if (jcr->dir_bsock) {
103                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
104             }
105             last_heartbeat = now;
106          }
107       }
108
109       /*
110        * Check if user unmounted the device while we were waiting
111        */
112       unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
113                    (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
114
115       if (stat != ETIMEDOUT) {     /* we blocked the device */
116          break;                    /* on error return */
117       }
118       if (dev->rem_wait_sec <= 0) {  /* on exceeding wait time return */
119          Dmsg0(400, "Exceed wait time.\n");
120          break;
121       }
122
123       if (!unmounted && dev->vol_poll_interval &&
124           (now - first_start >= dev->vol_poll_interval)) {
125          Dmsg1(400, "In wait blocked=%s\n", edit_blocked_reason(dev));
126          dev->poll = true;            /* returning a poll event */
127          break;
128       }
129       /*
130        * Check if user mounted the device while we were waiting
131        */
132       if (dev->dev_blocked == BST_MOUNT) {   /* mount request ? */
133          stat = 0;
134          break;
135       }
136
137       add_wait = dev->wait_sec - (now - start);
138       if (add_wait < 0) {
139          add_wait = 0;
140       }
141       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
142          add_wait = me->heartbeat_interval;
143       }
144    }
145
146    if (!unmounted) {
147       dev->dev_blocked = dev->dev_prev_blocked;    /* restore entry state */
148    }
149    V(dev->mutex);
150    return stat;
151 }
152
153
154 /*
155  * Wait for any device to be released, then we return, so 
156  *  higher level code can rescan possible devices.
157  * 
158  * Returns: true  if a device has changed state
159  *          false if the total wait time has expired.
160  */
161 bool wait_for_device(JCR *jcr, bool first)
162 {
163    struct timeval tv;
164    struct timezone tz;
165    struct timespec timeout;
166 // time_t last_heartbeat = 0;
167    int stat = 0;
168    int add_wait;
169    bool ok = false;
170
171    Dmsg0(100, "Enter wait_for_device\n");
172    P(device_release_mutex);
173
174    if (first) {
175       Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to obtain a device.\n"), jcr->Job);
176    }
177
178    /*
179     * Wait requested time (dev->rem_wait_sec).  However, we also wake up every
180     *    HB_TIME seconds and send a heartbeat to the FD and the Director
181     *    to keep stateful firewalls from closing them down while waiting
182     *    for the operator.
183     */
184    add_wait = jcr->rem_wait_sec;
185    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
186       add_wait = me->heartbeat_interval;
187    }
188
189    for ( ; !job_canceled(jcr); ) {
190       time_t now, start;
191
192       gettimeofday(&tv, &tz);
193       timeout.tv_nsec = tv.tv_usec * 1000;
194       timeout.tv_sec = tv.tv_sec + add_wait;
195
196       Dmsg3(100, "I'm going to wait for a device. HB=%d wait=%d remwait=%d\n", 
197          (int)me->heartbeat_interval, jcr->wait_sec, jcr->rem_wait_sec);
198       start = time(NULL);
199       /* Wait required time */
200       stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
201       Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat);
202
203       now = time(NULL);
204       jcr->rem_wait_sec -= (now - start);
205
206 #ifdef needed
207       /* Note, this always triggers the first time. We want that. */
208       if (me->heartbeat_interval) {
209          if (now - last_heartbeat >= me->heartbeat_interval) {
210             /* send heartbeats */
211             if (jcr->file_bsock) {
212                bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
213                Dmsg0(400, "Send heartbeat to FD.\n");
214             }
215             if (jcr->dir_bsock) {
216                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
217             }
218             last_heartbeat = now;
219          }
220       }
221 #endif
222
223       if (stat != ETIMEDOUT) {     /* if someone woke us up */
224          ok = true;
225          break;                    /* allow caller to examine device */
226       }
227       if (jcr->rem_wait_sec <= 0) {  /* on exceeding wait time return */
228          Dmsg0(400, "Exceed wait time.\n");
229          if (!double_jcr_wait_time(jcr)) {
230             break;                 /* give up */
231          }
232          Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to obtain a device.\n"), jcr->Job);
233       }
234
235       add_wait = jcr->wait_sec - (now - start);
236       if (add_wait < 0) {
237          add_wait = 0;
238       }
239       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
240          add_wait = me->heartbeat_interval;
241       }
242    }
243
244    V(device_release_mutex);
245    Dmsg1(100, "Return from wait_device ok=%d\n", ok);
246    return ok;
247 }
248
249 /*
250  * The jcr timers are used for waiting on any device *
251  * Returns: true if time doubled
252  *          false if max time expired
253  */
254 static bool double_jcr_wait_time(JCR *jcr)
255 {
256    jcr->wait_sec *= 2;               /* double wait time */
257    if (jcr->wait_sec > jcr->max_wait) {   /* but not longer than maxtime */
258       jcr->wait_sec = jcr->max_wait;
259    }
260    jcr->num_wait++;
261    jcr->rem_wait_sec = jcr->wait_sec;
262    if (jcr->num_wait >= jcr->max_num_wait) {
263       return false;
264    }
265    return true;
266 }