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