]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/wait.c
11Apr07
[bacula/bacula] / bacula / src / stored / wait.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 plus additions
11    that are listed 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 John Walker.
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 //static bool double_jcr_wait_time(JCR *jcr);
44
45
46 /*
47  * Wait for SysOp to mount a tape on a specific device
48  *
49  *   Returns: W_ERROR, W_TIMEOUT, W_POLL, W_MOUNT, or W_WAKE 
50  */
51 int wait_for_sysop(DCR *dcr)
52 {
53    struct timeval tv;
54    struct timezone tz;
55    struct timespec timeout;
56    time_t last_heartbeat = 0;
57    time_t first_start = time(NULL);
58    int stat = 0;
59    int add_wait;
60    bool unmounted;
61    DEVICE *dev = dcr->dev;
62    JCR *jcr = dcr->jcr;
63
64    dev->dlock();  
65    Dmsg1(100, "Enter blocked=%s\n", dev->print_blocked());
66    unmounted = is_device_unmounted(dev);
67
68    dev->poll = false;
69    /*
70     * Wait requested time (dev->rem_wait_sec).  However, we also wake up every
71     *    HB_TIME seconds and send a heartbeat to the FD and the Director
72     *    to keep stateful firewalls from closing them down while waiting
73     *    for the operator.
74     */
75    add_wait = dev->rem_wait_sec;
76    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
77       add_wait = me->heartbeat_interval;
78    }
79    /* If the user did not unmount the tape and we are polling, ensure
80     *  that we poll at the correct interval.
81     */
82    if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
83       add_wait = dev->vol_poll_interval;
84    }
85
86    if (!unmounted) {
87       Dmsg1(400, "blocked=%s\n", dev->print_blocked());
88       dev->dev_prev_blocked = dev->blocked();
89       dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
90    }
91
92    for ( ; !job_canceled(jcr); ) {
93       time_t now, start;
94
95       gettimeofday(&tv, &tz);
96       timeout.tv_nsec = tv.tv_usec * 1000;
97       timeout.tv_sec = tv.tv_sec + add_wait;
98
99       Dmsg4(400, "I'm going to sleep on device %s. HB=%d wait=%d add_wait=%d\n", 
100          dev->print_name(), (int)me->heartbeat_interval, dev->wait_sec, add_wait);
101       start = time(NULL);
102       /* Wait required time */
103       stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->m_mutex, &timeout);
104       Dmsg2(400, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
105          dev->print_blocked());
106
107       now = time(NULL);
108       dev->rem_wait_sec -= (now - start);
109
110       /* Note, this always triggers the first time. We want that. */
111       if (me->heartbeat_interval) {
112          if (now - last_heartbeat >= me->heartbeat_interval) {
113             /* send heartbeats */
114             if (jcr->file_bsock) {
115                bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
116                Dmsg0(400, "Send heartbeat to FD.\n");
117             }
118             if (jcr->dir_bsock) {
119                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
120             }
121             last_heartbeat = now;
122          }
123       }
124
125       if (stat == EINVAL) {
126          berrno be;
127          Jmsg1(jcr, M_FATAL, 0, _("pthread timedwait error. ERR=%s\n"), be.strerror(stat));
128          stat = W_ERROR;               /* error */
129          break;
130       }
131
132
133       if (dev->rem_wait_sec <= 0) {  /* on exceeding wait time return */
134          Dmsg0(400, "Exceed wait time.\n");
135          stat = W_TIMEOUT;
136          break;
137       }
138
139       /*
140        * Check if user unmounted the device while we were waiting
141        */
142       unmounted = is_device_unmounted(dev);
143
144       if (!unmounted && dev->vol_poll_interval &&
145           (now - first_start >= dev->vol_poll_interval)) {
146          Dmsg1(400, "In wait blocked=%s\n", dev->print_blocked());
147          dev->poll = true;            /* returning a poll event */
148          stat = W_POLL;
149          break;
150       }
151       /*
152        * Check if user mounted the device while we were waiting
153        */
154       if (dev->blocked() == BST_MOUNT) {   /* mount request ? */
155          stat = W_MOUNT;
156          break;
157       }
158
159       /*
160        * If we did not timeout, then some event happened, so
161        *   return to check if state changed.   
162        */
163       if (stat != 0) {
164          stat = W_WAKE;          /* someone woke us */
165          break;
166       }
167
168       /* 
169        * At this point, we know we woke up because of a timeout,
170        *   that was due to a heartbeat, so we just update
171        *   the wait counters and continue.
172        */
173       add_wait = dev->wait_sec - (now - start);
174       if (add_wait < 0) {
175          add_wait = 0;
176       }
177       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
178          add_wait = me->heartbeat_interval;
179       }
180    }
181
182    if (!unmounted) {
183       dev->set_blocked(dev->dev_prev_blocked);    /* restore entry state */
184       Dmsg1(400, "set %s\n", dev->print_blocked());
185    }
186    Dmsg1(400, "Exit blocked=%s\n", dev->print_blocked());
187    dev->dunlock();
188    return stat;
189 }
190
191
192 /*
193  * Wait for any device to be released, then we return, so 
194  *  higher level code can rescan possible devices.
195  * 
196  * Returns: true  if a device has changed state
197  *          false if the total wait time has expired.
198  */
199 bool wait_for_device(JCR *jcr, bool first)
200 {
201    struct timeval tv;
202    struct timezone tz;
203    struct timespec timeout;
204    int stat = 0;
205    bool ok = true;
206    const int wait_time = 5 * 60;       /* wait 5 minutes */
207
208    Dmsg0(100, "Enter wait_for_device\n");
209    P(device_release_mutex);
210
211    if (first) {
212       Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to reserve a device.\n"), jcr->Job);
213    }
214
215    gettimeofday(&tv, &tz);
216    timeout.tv_nsec = tv.tv_usec * 1000;
217    timeout.tv_sec = tv.tv_sec + wait_time;
218
219    Dmsg0(100, "I'm going to wait for a device.\n");
220
221    /* Wait required time */
222    stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
223    Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat);
224
225
226    V(device_release_mutex);
227    Dmsg1(100, "Return from wait_device ok=%d\n", ok);
228    return ok;
229 }
230
231 #ifdef xxx
232 /*
233  * The jcr timers are used for waiting on any device *
234  * Returns: true if time doubled
235  *          false if max time expired
236  */
237 static bool double_jcr_wait_time(JCR *jcr)
238 {
239    jcr->wait_sec *= 2;               /* double wait time */
240    if (jcr->wait_sec > jcr->max_wait) {   /* but not longer than maxtime */
241       jcr->wait_sec = jcr->max_wait;
242    }
243    jcr->num_wait++;
244    jcr->rem_wait_sec = jcr->wait_sec;
245    if (jcr->num_wait >= jcr->max_num_wait) {
246       return false;
247    }
248    return true;
249 }
250 #endif