]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/wait.c
Fix files wiped out by merge
[bacula/bacula] / bacula / src / stored / wait.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Subroutines to handle waiting for operator intervention
30  *   or waiting for a Device to be released
31  *
32  *  Code for wait_for_sysop() pulled from askdir.c
33  *
34  *   Kern Sibbald, March 2005
35  *
36  *   Version $Id$
37  */
38
39
40 #include "bacula.h"                   /* pull in global headers */
41 #include "stored.h"                   /* pull in Storage Deamon headers */
42
43 const int dbglvl = 400;
44
45 /*
46  * Wait for SysOp to mount a tape on a specific device
47  *
48  *   Returns: W_ERROR, W_TIMEOUT, W_POLL, W_MOUNT, or W_WAKE 
49  */
50 int wait_for_sysop(DCR *dcr)
51 {
52    struct timeval tv;
53    struct timezone tz;
54    struct timespec timeout;
55    time_t last_heartbeat = 0;
56    time_t first_start = time(NULL);
57    int stat = 0;
58    int add_wait;
59    bool unmounted;
60    DEVICE *dev = dcr->dev;
61    JCR *jcr = dcr->jcr;
62
63    dev->dlock();  
64    Dmsg1(dbglvl, "Enter blocked=%s\n", dev->print_blocked());
65
66    /*
67     * Since we want to mount a tape, make sure current one is
68     *  not marked as using this drive.
69     */
70    volume_unused(dcr);
71
72    unmounted = dev->is_device_unmounted();
73    dev->poll = false;
74    /*
75     * Wait requested time (dev->rem_wait_sec).  However, we also wake up every
76     *    HB_TIME seconds and send a heartbeat to the FD and the Director
77     *    to keep stateful firewalls from closing them down while waiting
78     *    for the operator.
79     */
80    add_wait = dev->rem_wait_sec;
81    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
82       add_wait = me->heartbeat_interval;
83    }
84    /* If the user did not unmount the tape and we are polling, ensure
85     *  that we poll at the correct interval.
86     */
87    if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
88       add_wait = dev->vol_poll_interval;
89    }
90
91    if (!unmounted) {
92       Dmsg1(dbglvl, "blocked=%s\n", dev->print_blocked());
93       dev->dev_prev_blocked = dev->blocked();
94       dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
95    }
96
97    for ( ; !job_canceled(jcr); ) {
98       time_t now, start, total_waited;
99
100       gettimeofday(&tv, &tz);
101       timeout.tv_nsec = tv.tv_usec * 1000;
102       timeout.tv_sec = tv.tv_sec + add_wait;
103
104       Dmsg4(dbglvl, "I'm going to sleep on device %s. HB=%d rem_wait=%d add_wait=%d\n", 
105          dev->print_name(), (int)me->heartbeat_interval, dev->rem_wait_sec, add_wait);
106       start = time(NULL);
107       /* Wait required time */
108       stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->m_mutex, &timeout);
109       Dmsg2(dbglvl, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
110          dev->print_blocked());
111
112       now = time(NULL);
113       total_waited = now - first_start;
114       dev->rem_wait_sec -= (now - start);
115
116       /* Note, this always triggers the first time. We want that. */
117       if (me->heartbeat_interval) {
118          if (now - last_heartbeat >= me->heartbeat_interval) {
119             /* send heartbeats */
120             if (jcr->file_bsock) {
121                jcr->file_bsock->signal(BNET_HEARTBEAT);
122                Dmsg0(dbglvl, "Send heartbeat to FD.\n");
123             }
124             if (jcr->dir_bsock) {
125                jcr->dir_bsock->signal(BNET_HEARTBEAT);
126             }
127             last_heartbeat = now;
128          }
129       }
130
131       if (stat == EINVAL) {
132          berrno be;
133          Jmsg1(jcr, M_FATAL, 0, _("pthread timedwait error. ERR=%s\n"), be.bstrerror(stat));
134          stat = W_ERROR;               /* error */
135          break;
136       }
137
138
139       if (dev->rem_wait_sec <= 0) {  /* on exceeding wait time return */
140          Dmsg0(dbglvl, "Exceed wait time.\n");
141          stat = W_TIMEOUT;
142          break;
143       }
144
145       /*
146        * Check if user unmounted the device while we were waiting
147        */
148       unmounted = dev->is_device_unmounted();
149
150       if (!unmounted && dev->vol_poll_interval &&
151           (total_waited >= dev->vol_poll_interval)) {
152          Dmsg1(dbglvl, "poll return in wait blocked=%s\n", dev->print_blocked());
153          dev->poll = true;            /* returning a poll event */
154          stat = W_POLL;
155          break;
156       }
157       /*
158        * Check if user mounted the device while we were waiting
159        */
160       if (dev->blocked() == BST_MOUNT) {   /* mount request ? */
161          Dmsg0(dbglvl, "Mounted return.\n");
162          stat = W_MOUNT;
163          break;
164       }
165
166       /*
167        * If we did not timeout, then some event happened, so
168        *   return to check if state changed.   
169        */
170       if (stat != ETIMEDOUT) {
171          berrno be;
172          Dmsg2(dbglvl, "Wake return. stat=%d. ERR=%s\n", stat, be.bstrerror(stat));
173          stat = W_WAKE;          /* someone woke us */
174          break;
175       }
176
177       /* 
178        * At this point, we know we woke up because of a timeout,
179        *   that was due to a heartbeat, because any other reason would
180        *   have caused us to return, so update the wait counters and continue.
181        */
182       add_wait = dev->rem_wait_sec;
183       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
184          add_wait = me->heartbeat_interval;
185       }
186       /* If the user did not unmount the tape and we are polling, ensure
187        *  that we poll at the correct interval.
188        */
189       if (!unmounted && dev->vol_poll_interval && 
190            add_wait > dev->vol_poll_interval - total_waited) {
191          add_wait = dev->vol_poll_interval - total_waited;
192       }
193       if (add_wait < 0) {
194          add_wait = 0;
195       }
196    }
197
198    if (!unmounted) {
199       dev->set_blocked(dev->dev_prev_blocked);    /* restore entry state */
200       Dmsg1(dbglvl, "set %s\n", dev->print_blocked());
201    }
202    Dmsg1(dbglvl, "Exit blocked=%s\n", dev->print_blocked());
203    dev->dunlock();
204    return stat;
205 }
206
207
208 /*
209  * Wait for any device to be released, then we return, so 
210  *  higher level code can rescan possible devices.  Since there
211  *  could be a job waiting for a drive to free up, we wait a maximum
212  *  of 1 minute then retry just in case a broadcast was lost, and 
213  *  we return to rescan the devices.
214  * 
215  * Returns: true  if a device has changed state
216  *          false if the total wait time has expired.
217  */
218 bool wait_for_device(JCR *jcr, int &retries)
219 {
220    struct timeval tv;
221    struct timezone tz;
222    struct timespec timeout;
223    int stat = 0;
224    bool ok = true;
225    const int max_wait_time = 1 * 60;       /* wait 1 minute */
226    char ed1[50];
227
228    Dmsg0(dbglvl, "Enter wait_for_device\n");
229    P(device_release_mutex);
230
231    if (++retries % 5 == 0) {
232       /* Print message every 5 minutes */
233       Jmsg(jcr, M_MOUNT, 0, _("JobId=%s, Job %s waiting to reserve a device.\n"), 
234          edit_uint64(jcr->JobId, ed1), jcr->Job);
235    }
236
237    gettimeofday(&tv, &tz);
238    timeout.tv_nsec = tv.tv_usec * 1000;
239    timeout.tv_sec = tv.tv_sec + max_wait_time;
240
241    Dmsg0(dbglvl, "Going to wait for a device.\n");
242
243    /* Wait required time */
244    stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
245    Dmsg1(dbglvl, "Wokeup from sleep on device stat=%d\n", stat);
246
247    V(device_release_mutex);
248    Dmsg1(dbglvl, "Return from wait_device ok=%d\n", ok);
249    return ok;
250 }
251
252 #ifdef xxx
253 /*
254  * The jcr timers are used for waiting on any device *
255  * Returns: true if time doubled
256  *          false if max time expired
257  */
258 static bool double_jcr_wait_time(JCR *jcr)
259 {
260    jcr->wait_sec *= 2;               /* double wait time */
261    if (jcr->wait_sec > jcr->max_wait) {   /* but not longer than maxtime */
262       jcr->wait_sec = jcr->max_wait;
263    }
264    jcr->num_wait++;
265    jcr->rem_wait_sec = jcr->wait_sec;
266    if (jcr->num_wait >= jcr->max_num_wait) {
267       return false;
268    }
269    return true;
270 }
271 #endif