3a358cef40705b31d050f3d641e6d9b1d54ab91c
[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     return NULL;
487 }