Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / butc / dbentries.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #include <rx/xdr.h>
16 #include <rx/rx.h>
17 #include <lwp.h>
18 #include <lock.h>
19 #include <afs/tcdata.h>
20 #include <afs/bubasics.h>
21 #include <afs/budb_client.h>
22 #include <afs/afsint.h>
23 #include <afs/vldbint.h>
24 #include <afs/vlserver.h>
25 #include <afs/volser.h>
26 #include <afs/volint.h>
27 #include <afs/cellconfig.h>
28 #include <afs/bucoord_prototypes.h>
29
30 #include "butc_internal.h"
31 #include "error_macros.h"
32
33 dlqlinkT savedEntries;
34 dlqlinkT entries_to_flush;
35
36 int dbWatcherinprogress;
37
38 afs_int32
39 threadEntryDir(void *anEntry, afs_int32 size, afs_int32 type)
40 {
41 dlqlinkP entryPtr;
42 void *entry = NULL;
43 int tried;
44
45 for (tried = 0; tried < 5; tried++) {
46 entryPtr = malloc(sizeof(dlqlinkT));
47 entry = malloc(size);
48 if (entryPtr && entry)
49 break;
50
51 /* sleep a minute and try again */
52 if (entryPtr)
53 free(entryPtr);
54 if (entry)
55 free(entry);
56
57 if ((tried > 0) && !dbWatcherinprogress)
58 return (TC_NOMEMORY);
59 #ifdef AFS_PTHREAD_ENV
60 sleep(60);
61 #else
62 IOMGR_Sleep(60);
63 #endif
64 }
65 entryPtr->dlq_prev = entryPtr->dlq_next = (dlqlinkP) NULL;
66 entryPtr->dlq_type = type;
67 entryPtr->dlq_structPtr = entry;
68
69 memcpy(entry, anEntry, size);
70 dlqLinkb(&entries_to_flush, entryPtr);
71 return (0);
72 }
73
74 /*
75 * threadEntry.
76 * Creates an entry and puts it onto the savedEntries list.
77 * Will retry up to 5 times if not enough memory. Hopfully, the
78 * Watcher thread will free up some memory for it to continue.
79 */
80
81 afs_int32
82 threadEntry(void *anEntry, afs_int32 size, afs_int32 type)
83 {
84 dlqlinkP entryPtr;
85 void *entry = NULL;
86 int tried;
87
88 for (tried = 0; tried < 5; tried++) {
89 entryPtr = (dlqlinkP) malloc(sizeof(dlqlinkT));
90 entry = malloc(size);
91 if (entryPtr && entry)
92 break;
93
94 /* sleep a minute and try again */
95 if (entryPtr)
96 free(entryPtr);
97 if (entry)
98 free(entry);
99
100 if ((tried > 0) && !dbWatcherinprogress)
101 return (TC_NOMEMORY);
102 #ifdef AFS_PTHREAD_ENV
103 sleep(60);
104 #else
105 IOMGR_Sleep(60);
106 #endif
107 }
108
109 entryPtr->dlq_prev = entryPtr->dlq_next = (dlqlinkP) NULL;
110 entryPtr->dlq_type = type;
111 entryPtr->dlq_structPtr = entry;
112
113 memcpy(entry, anEntry, size);
114 dlqLinkb(&savedEntries, (dlqlinkP) entryPtr);
115 return (0);
116 }
117
118 /* ------------------------------------------------------------------ */
119
120 afs_int32
121 useDump(struct budb_dumpEntry *dumpEntryPtr)
122 {
123 afs_int32 code = 0;
124
125 code =
126 threadEntry(dumpEntryPtr, sizeof(struct budb_dumpEntry), DLQ_USEDUMP);
127 return (code);
128 }
129
130 /*
131 * finishDump
132 * Creates a dump entry (finished) and puts it onto the savedEntries list.
133 */
134 afs_int32
135 finishDump(struct budb_dumpEntry *aDumpEntryPtr)
136 {
137 afs_int32 code = 0;
138
139 code =
140 threadEntry(aDumpEntryPtr, sizeof(struct budb_dumpEntry),
141 DLQ_FINISHDUMP);
142 return (code);
143 }
144
145 /*
146 * useTape
147 * Creates a tape entry and puts it onto the savedEntries list.
148 */
149 afs_int32
150 useTape(struct budb_tapeEntry *aTapeEntryPtr, afs_int32 dumpID,
151 char *tapename, afs_int32 tapeSeq, afs_int32 useCount,
152 Date written, Date expiration, afs_int32 tapepos)
153 {
154 afs_int32 code = 0;
155
156 memset(aTapeEntryPtr, 0, sizeof(struct budb_tapeEntry));
157 strcpy(aTapeEntryPtr->name, tapename);
158 aTapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
159 aTapeEntryPtr->written = written; /* When label was written */
160 aTapeEntryPtr->expires = expiration;
161 aTapeEntryPtr->seq = tapeSeq;
162 aTapeEntryPtr->useCount = useCount;
163 aTapeEntryPtr->dump = dumpID;
164 aTapeEntryPtr->labelpos = tapepos;
165
166 code =
167 threadEntry(aTapeEntryPtr, sizeof(struct budb_tapeEntry),
168 DLQ_USETAPE);
169 return (code);
170 }
171
172 /*
173 * finishTape
174 * Creates a tape entry (finished) and puts it onto the savedEntries list.
175 */
176 afs_int32
177 finishTape(struct budb_tapeEntry *aTapeEntryPtr, afs_int32 useKBytes)
178 {
179 afs_int32 code = 0;
180
181 aTapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
182 aTapeEntryPtr->useKBytes = useKBytes;
183
184 code =
185 threadEntry(aTapeEntryPtr, sizeof(struct budb_tapeEntry),
186 DLQ_FINISHTAPE);
187 return (code);
188 }
189
190 /*
191 * addVolume
192 * Creates a volume entry and puts it onto the savedEntries list.
193 */
194 afs_int32
195 addVolume(struct budb_volumeEntry *aVolEntryPtr, afs_int32 dumpID,
196 char *tapename, char *volname, afs_int32 volid,
197 Date cloneDate, afs_int32 startPos, afs_int32 volBytes,
198 int fragment, afs_int32 flags)
199 {
200 afs_int32 code = 0;
201 int allo = 0;
202
203 if (!aVolEntryPtr) {
204 aVolEntryPtr = (struct budb_volumeEntry *)
205 malloc(sizeof(struct budb_volumeEntry));
206 if (!aVolEntryPtr)
207 ERROR_EXIT(TC_NOMEMORY);
208 allo = 1;
209 }
210
211 memset(aVolEntryPtr, 0, sizeof(struct budb_volumeEntry));
212 strcpy(aVolEntryPtr->name, volname);
213 aVolEntryPtr->flags = flags;
214 aVolEntryPtr->id = volid;
215 aVolEntryPtr->position = startPos;
216 aVolEntryPtr->clone = cloneDate;
217 aVolEntryPtr->nBytes = volBytes;
218 aVolEntryPtr->seq = fragment;
219 aVolEntryPtr->dump = dumpID;
220 strcpy(aVolEntryPtr->tape, tapename);
221
222 code =
223 threadEntry(aVolEntryPtr, sizeof(struct budb_volumeEntry),
224 DLQ_VOLENTRY);
225
226 error_exit:
227 if (code && allo)
228 free(aVolEntryPtr);
229 return (code);
230 }
231
232 static_inline int
233 freeEntry(void *e)
234 {
235 free(e);
236 return 0;
237 }
238
239 /*
240 * flushSavedEntries
241 * Runs through the list of savedEntries and adds the volumes and
242 * tapes to the database.
243 * A status of DUMP_NORETRYEOT means the tape(s) contains no useful data,
244 * and tapes and volumes should not be added to the DB.
245 */
246 afs_int32
247 flushSavedEntries(afs_int32 status)
248 {
249 dlqlinkP entryPtr;
250 struct budb_tapeEntry *tapePtr;
251 struct budb_volumeEntry *volPtr;
252 afs_int32 code = 0;
253
254 /*
255 * On DUMP_NORETRYEOT, the volume being dumped was the first on the tape and hit the
256 * EOT. This means the volume is larger than the tape. Instead of going onto the next
257 * tape, backup reuses the tape. Thus, we must remove this tape entry and free it
258 * without adding it to the backup database.
259 */
260 if (status == DUMP_NORETRYEOT) {
261 entryPtr = dlqUnlinkb(&savedEntries);
262 if (!entryPtr || (entryPtr->dlq_type != DLQ_USETAPE))
263 ERROR_EXIT(TC_INTERNALERROR);
264
265 tapePtr = (struct budb_tapeEntry *)entryPtr->dlq_structPtr;
266 if (tapePtr)
267 free(tapePtr);
268 if (entryPtr)
269 free(entryPtr);
270 }
271
272 /*
273 * Add dump, tape, and volume entries to the list for the dbWatcher to
274 * flush. Volume entries are not added if the volume failed to dump.
275 */
276 while ((entryPtr = dlqUnlinkf(&savedEntries))) {
277 if ((entryPtr->dlq_type == DLQ_VOLENTRY) && (status != DUMP_SUCCESS)) {
278 volPtr = (struct budb_volumeEntry *)entryPtr->dlq_structPtr;
279 if (volPtr)
280 free(volPtr);
281 if (entryPtr)
282 free(entryPtr);
283 } else {
284 dlqLinkb(&entries_to_flush, entryPtr);
285 }
286 }
287
288 error_exit:
289 /* Free anything that remains on dlq */
290 dlqTraverseQueue(&savedEntries, freeEntry, freeEntry);
291 return (code);
292 }
293
294 void
295 waitDbWatcher(void)
296 {
297 int message = 0;
298
299 while (dbWatcherinprogress || !dlqEmpty(&entries_to_flush)) {
300 if (!message) {
301 printf("Updating database\n");
302 message++;
303 }
304 #ifdef AFS_PTHREAD_ENV
305 sleep(2);
306 #else
307 IOMGR_Sleep(2);
308 #endif
309 }
310
311 if (message) {
312 printf("Updating database - done\n");
313 }
314 return;
315 }
316
317 #define MAXVOLUMESTOADD 100
318 int addvolumes = 1;
319
320 void *
321 dbWatcher(void *unused)
322 {
323 dlqlinkP entryPtr;
324 struct budb_dumpEntry *dumpPtr;
325 struct budb_tapeEntry *tapePtr;
326 struct budb_volumeEntry *volPtr, volumes[MAXVOLUMESTOADD];
327 afs_int32 new;
328 afs_int32 code = 0;
329 int i, c, addedDump;
330
331 afs_pthread_setname_self("dbWatcher");
332 dlqInit(&entries_to_flush);
333 dlqInit(&savedEntries);
334
335 dbWatcherinprogress = 0;
336 addedDump = 1;
337 while (1) {
338 /*while */
339 /* Add tape and volume enties to the backup database */
340 while ((entryPtr = dlqUnlinkf(&entries_to_flush))) {
341 dbWatcherinprogress = 1;
342
343 if (!entryPtr->dlq_structPtr) {
344 ErrorLog(0, 0, TC_BADQUEUE, 0,
345 "Warning: Invalid database entry - nota added\n");
346 } else
347 switch (entryPtr->dlq_type) {
348 case DLQ_USEDUMP:
349 dumpPtr =
350 (struct budb_dumpEntry *)entryPtr->dlq_structPtr;
351 /* Now call the database to create the entry */
352 code = bcdb_CreateDump(dumpPtr);
353 if (code) {
354 if (code == BUDB_DUMPIDEXISTS) {
355 printf
356 ("Dump %s (DumpID %u) already exists in backup database\n",
357 dumpPtr->name, dumpPtr->id);
358 } else {
359 ErrorLog(0, 0, code, 0,
360 "Warning: Can't create dump %s (DumpID %u) in backup database\n",
361 dumpPtr->name, dumpPtr->id);
362 }
363 }
364 addedDump = (code ? 0 : 1);
365 break;
366
367 case DLQ_FINISHDUMP:
368 dumpPtr =
369 (struct budb_dumpEntry *)entryPtr->dlq_structPtr;
370 if (addedDump) {
371 code = bcdb_FinishDump(dumpPtr);
372 if (code) {
373 ErrorLog(0, 0, code, 0,
374 "Warning: Can't finish dump %s (DumpID %u) in backup database\n",
375 dumpPtr->name, dumpPtr->id);
376 }
377 }
378 addedDump = 1;
379 break;
380
381 case DLQ_USETAPE:
382 tapePtr =
383 (struct budb_tapeEntry *)entryPtr->dlq_structPtr;
384 if (addedDump) {
385 code = bcdb_UseTape(tapePtr, &new);
386 if (code) {
387 ErrorLog(0, 0, code, 0,
388 "Warning: Can't add tape %s of DumpID %u to backup database\n",
389 tapePtr->name, tapePtr->dump);
390 }
391 }
392 break;
393
394 case DLQ_FINISHTAPE:
395 tapePtr =
396 (struct budb_tapeEntry *)entryPtr->dlq_structPtr;
397 if (addedDump) {
398 code = bcdb_FinishTape(tapePtr);
399 if (code) {
400 ErrorLog(0, 0, code, 0,
401 "Warning: Can't finish tape %s of DumpID %u in backup database\n",
402 tapePtr->name, tapePtr->dump);
403 }
404 }
405 break;
406
407 case DLQ_VOLENTRY:
408 /* collect array of volumes to add to the dump */
409 for (c = 0; c < MAXVOLUMESTOADD; c++) {
410 if (c > 0) { /* don't read the 1st - already did */
411 entryPtr = dlqUnlinkf(&entries_to_flush); /* Get the next entry */
412 if (!entryPtr)
413 break;
414 }
415
416 if (entryPtr->dlq_type != DLQ_VOLENTRY) {
417 /* Place back onto list and add the vol entries we have */
418 dlqLinkf(&entries_to_flush, entryPtr);
419 entryPtr = (dlqlinkP) 0; /* don't want to deallocate below */
420 break;
421 }
422
423 volPtr =
424 (struct budb_volumeEntry *)entryPtr->
425 dlq_structPtr;
426 if (!volPtr) {
427 ErrorLog(0, 0, TC_BADQUEUE, 0,
428 "Warning: Invalid database entry - not added\n");
429 break;
430 }
431
432 memcpy(&volumes[c], volPtr,
433 sizeof(struct budb_volumeEntry));
434 free(volPtr);
435 free(entryPtr);
436 entryPtr = (dlqlinkP) 0;
437 }
438
439 if (addedDump) {
440 if (addvolumes) {
441 code = bcdb_AddVolumes(&volumes[0], c);
442 if (code) {
443 if (code < 0)
444 addvolumes = 0;
445 else {
446 ErrorLog(0, 0, code, 0,
447 "Warning: Can't add %d volumes to dumpid %u\n",
448 c, volumes[0].dump);
449 }
450 }
451 }
452 if (!addvolumes) {
453 for (i = 0; i < c; i++) {
454 code = bcdb_AddVolume(&volumes[i]);
455 if (code) {
456 ErrorLog(0, 0, code, 0,
457 "Warning: Can't add volume %s %u to backup database\n",
458 volumes[i].name, volumes[i].id);
459 }
460 }
461 }
462 }
463 break;
464
465 default:
466 ErrorLog(0, 0, 0, 0,
467 "Warning: dbWatcher: Unrecognized entry type %d\n",
468 entryPtr->dlq_type);
469 break; /* ignore */
470 }
471
472 if (entryPtr) {
473 if (entryPtr->dlq_structPtr)
474 free(entryPtr->dlq_structPtr);
475 free(entryPtr);
476 }
477 } /*while */
478
479 dbWatcherinprogress = 0;
480 #ifdef AFS_PTHREAD_ENV
481 sleep(2);
482 #else
483 IOMGR_Sleep(2);
484 #endif
485 }
486 AFS_UNREACHED(return(NULL));
487 }