37abf66fb8376fa57df57037685a91363269eb14
[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 RCSID
14     ("$Header$");
15
16 #include <sys/types.h>
17 #ifdef AFS_NT40_ENV
18 #include <winsock2.h>
19 #else
20 #include <sys/file.h>
21 #include <netinet/in.h>
22 #include <sys/socket.h>
23 #include <sys/time.h>
24 #include <netdb.h>
25 #endif
26 #include <stdlib.h>
27 #include <string.h>
28 #include <rx/xdr.h>
29 #include <rx/rx.h>
30 #include <lwp.h>
31 #include <lock.h>
32 #include <afs/tcdata.h>
33 #include <afs/bubasics.h>
34 #include <afs/budb_client.h>
35 #include <afs/vldbint.h>
36
37 #include <afs/vlserver.h>
38 #include <afs/volser.h>
39 #include <afs/volint.h>
40 #include <afs/cellconfig.h>
41
42 #include "error_macros.h"
43
44 dlqlinkT savedEntries;
45 dlqlinkT entries_to_flush;
46
47 int dbWatcherinprogress;
48
49 afs_int32
50 threadEntryDir(char *anEntry, afs_int32 size, afs_int32 type)
51 {
52     dlqlinkP entryPtr;
53     char *entry = NULL;
54     int tried;
55
56     for (tried = 0; tried < 5; tried++) {
57         entryPtr = (dlqlinkP) malloc(sizeof(dlqlinkT));
58         entry = (char *)malloc(size);
59         if (entryPtr && entry)
60             break;
61
62         /* sleep a minute and try again */
63         if (entryPtr)
64             free(entryPtr);
65         if (entry)
66             free(entry);
67
68         if ((tried > 0) && !dbWatcherinprogress)
69             return (TC_NOMEMORY);
70 #ifdef AFS_PTHREAD_ENV
71         sleep(60);
72 #else
73         IOMGR_Sleep(60);
74 #endif
75     }
76     entryPtr->dlq_prev = entryPtr->dlq_next = (dlqlinkP) NULL;
77     entryPtr->dlq_type = type;
78     entryPtr->dlq_structPtr = entry;
79
80     memcpy(entry, anEntry, size);
81     dlqLinkb(&entries_to_flush, entryPtr);
82     return (0);
83 }
84
85 /*
86  * threadEntry.
87  *     Creates an entry and puts it onto the savedEntries list.
88  *     Will retry up to 5 times if not enough memory. Hopfully, the 
89  *     Watcher thread will free up some memory for it to continue.
90  */
91
92 afs_int32
93 threadEntry(char *anEntry, afs_int32 size, afs_int32 type)
94 {
95     dlqlinkP entryPtr;
96     char *entry = NULL;
97     int tried;
98
99     for (tried = 0; tried < 5; tried++) {
100         entryPtr = (dlqlinkP) malloc(sizeof(dlqlinkT));
101         entry = (char *)malloc(size);
102         if (entryPtr && entry)
103             break;
104
105         /* sleep a minute and try again */
106         if (entryPtr)
107             free(entryPtr);
108         if (entry)
109             free(entry);
110
111         if ((tried > 0) && !dbWatcherinprogress)
112             return (TC_NOMEMORY);
113 #ifdef AFS_PTHREAD_ENV
114         sleep(60);
115 #else
116         IOMGR_Sleep(60);
117 #endif
118     }
119
120     entryPtr->dlq_prev = entryPtr->dlq_next = (dlqlinkP) NULL;
121     entryPtr->dlq_type = type;
122     entryPtr->dlq_structPtr = entry;
123
124     memcpy(entry, anEntry, size);
125     dlqLinkb(&savedEntries, (dlqlinkP) entryPtr);
126     return (0);
127 }
128
129 /* ------------------------------------------------------------------ */
130
131 afs_int32
132 useDump(struct budb_dumpEntry *dumpEntryPtr)
133 {
134     afs_int32 code = 0;
135
136     code =
137         threadEntry(dumpEntryPtr, sizeof(struct budb_dumpEntry), DLQ_USEDUMP);
138     return (code);
139 }
140
141 /*
142  * finishDump
143  *     Creates a dump entry (finished) and puts it onto the savedEntries list.
144  */
145 afs_int32
146 finishDump(struct budb_dumpEntry *aDumpEntryPtr)
147 {
148     afs_int32 code = 0;
149
150     code =
151         threadEntry(aDumpEntryPtr, sizeof(struct budb_dumpEntry),
152                     DLQ_FINISHDUMP);
153     return (code);
154 }
155
156 /*
157  * useTape
158  *     Creates a tape entry and puts it onto the savedEntries list.
159  */
160 afs_int32
161 useTape(struct budb_tapeEntry *aTapeEntryPtr, afs_int32 dumpID, char *tapename, afs_int32 tapeSeq, afs_int32 useCount, Date written, Date expiration, afs_int32 tapepos)
162 {
163     afs_int32 code = 0;
164
165     memset(aTapeEntryPtr, 0, sizeof(struct budb_tapeEntry));
166     strcpy(aTapeEntryPtr->name, tapename);
167     aTapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
168     aTapeEntryPtr->written = written;   /* When label was written */
169     aTapeEntryPtr->expires = expiration;
170     aTapeEntryPtr->seq = tapeSeq;
171     aTapeEntryPtr->useCount = useCount;
172     aTapeEntryPtr->dump = dumpID;
173     aTapeEntryPtr->labelpos = tapepos;
174
175     code =
176         threadEntry(aTapeEntryPtr, sizeof(struct budb_tapeEntry),
177                     DLQ_USETAPE);
178     return (code);
179 }
180
181 /*
182  * finishTape
183  *     Creates a tape entry (finished) and puts it onto the savedEntries list.
184  */
185 afs_int32
186 finishTape(struct budb_tapeEntry *aTapeEntryPtr, afs_int32 useKBytes)
187 {
188     afs_int32 code = 0;
189
190     aTapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
191     aTapeEntryPtr->useKBytes = useKBytes;
192
193     code =
194         threadEntry(aTapeEntryPtr, sizeof(struct budb_tapeEntry),
195                     DLQ_FINISHTAPE);
196     return (code);
197 }
198
199 /*
200  * addVolume
201  *     Creates a volume entry and puts it onto the savedEntries list.
202  */
203 afs_int32
204 addVolume(struct budb_volumeEntry *aVolEntryPtr, afs_int32 dumpID, char *tapename, char *volname, afs_int32 volid, Date cloneDate, afs_int32 startPos, afs_int32 volBytes, int fragment, afs_int32 flags)
205 {
206     afs_int32 code = 0;
207     int allo = 0;
208
209     if (!aVolEntryPtr) {
210         aVolEntryPtr = (struct budb_volumeEntry *)
211             malloc(sizeof(struct budb_volumeEntry));
212         if (!aVolEntryPtr)
213             ERROR_EXIT(TC_NOMEMORY);
214         allo = 1;
215     }
216
217     memset(aVolEntryPtr, 0, sizeof(struct budb_volumeEntry));
218     strcpy(aVolEntryPtr->name, volname);
219     aVolEntryPtr->flags = flags;
220     aVolEntryPtr->id = volid;
221     aVolEntryPtr->position = startPos;
222     aVolEntryPtr->clone = cloneDate;
223     aVolEntryPtr->nBytes = volBytes;
224     aVolEntryPtr->seq = fragment;
225     aVolEntryPtr->dump = dumpID;
226     strcpy(aVolEntryPtr->tape, tapename);
227
228     code =
229         threadEntry(aVolEntryPtr, sizeof(struct budb_volumeEntry),
230                     DLQ_VOLENTRY);
231
232   error_exit:
233     if (code && allo)
234         free(aVolEntryPtr);
235     return (code);
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, free, free);
290     return (code);
291 }
292
293 void
294 waitDbWatcher()
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()
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     dlqInit(&entries_to_flush);
331     dlqInit(&savedEntries);
332
333     dbWatcherinprogress = 0;
334     addedDump = 1;
335     while (1) {
336         /*while */
337         /* Add tape and volume enties to the backup database */
338         while (entryPtr = dlqUnlinkf(&entries_to_flush)) {
339             dbWatcherinprogress = 1;
340
341             if (!entryPtr->dlq_structPtr) {
342                 ErrorLog(0, 0, TC_BADQUEUE, 0,
343                          "Warning: Invalid database entry - nota added\n");
344             } else
345                 switch (entryPtr->dlq_type) {
346                 case DLQ_USEDUMP:
347                     dumpPtr =
348                         (struct budb_dumpEntry *)entryPtr->dlq_structPtr;
349                     /* Now call the database to create the entry */
350                     code = bcdb_CreateDump(dumpPtr);
351                     if (code) {
352                         if (code == BUDB_DUMPIDEXISTS) {
353                             printf
354                                 ("Dump %s (DumpID %u) already exists in backup database\n",
355                                  dumpPtr->name, dumpPtr->id);
356                         } else {
357                             ErrorLog(0, 0, code, 0,
358                                      "Warning: Can't create dump %s (DumpID %u) in backup database\n",
359                                      dumpPtr->name, dumpPtr->id);
360                         }
361                     }
362                     addedDump = (code ? 0 : 1);
363                     break;
364
365                 case DLQ_FINISHDUMP:
366                     dumpPtr =
367                         (struct budb_dumpEntry *)entryPtr->dlq_structPtr;
368                     if (addedDump) {
369                         code = bcdb_FinishDump(dumpPtr);
370                         if (code) {
371                             ErrorLog(0, 0, code, 0,
372                                      "Warning: Can't finish dump %s (DumpID %u) in backup database\n",
373                                      dumpPtr->name, dumpPtr->id);
374                         }
375                     }
376                     addedDump = 1;
377                     break;
378
379                 case DLQ_USETAPE:
380                     tapePtr =
381                         (struct budb_tapeEntry *)entryPtr->dlq_structPtr;
382                     if (addedDump) {
383                         code = bcdb_UseTape(tapePtr, &new);
384                         if (code) {
385                             ErrorLog(0, 0, code, 0,
386                                      "Warning: Can't add tape %s of DumpID %u to backup database\n",
387                                      tapePtr->name, tapePtr->dump);
388                         }
389                     }
390                     break;
391
392                 case DLQ_FINISHTAPE:
393                     tapePtr =
394                         (struct budb_tapeEntry *)entryPtr->dlq_structPtr;
395                     if (addedDump) {
396                         code = bcdb_FinishTape(tapePtr, &new);
397                         if (code) {
398                             ErrorLog(0, 0, code, 0,
399                                      "Warning: Can't finish tape %s of DumpID %u in backup database\n",
400                                      tapePtr->name, tapePtr->dump);
401                         }
402                     }
403                     break;
404
405                 case DLQ_VOLENTRY:
406                     /* collect array of volumes to add to the dump */
407                     for (c = 0; c < MAXVOLUMESTOADD; c++) {
408                         if (c > 0) {    /* don't read the 1st - already did */
409                             entryPtr = dlqUnlinkf(&entries_to_flush);   /* Get the next entry */
410                             if (!entryPtr)
411                                 break;
412                         }
413
414                         if (entryPtr->dlq_type != DLQ_VOLENTRY) {
415                             /* Place back onto list and add the vol entries we have */
416                             dlqLinkf(&entries_to_flush, entryPtr);
417                             entryPtr = (dlqlinkP) 0;    /* don't want to deallocate below */
418                             break;
419                         }
420
421                         volPtr =
422                             (struct budb_volumeEntry *)entryPtr->
423                             dlq_structPtr;
424                         if (!volPtr) {
425                             ErrorLog(0, 0, TC_BADQUEUE, 0,
426                                      "Warning: Invalid database entry - not added\n");
427                             break;
428                         }
429
430                         memcpy(&volumes[c], volPtr,
431                                sizeof(struct budb_volumeEntry));
432                         free(volPtr);
433                         free(entryPtr);
434                         entryPtr = (dlqlinkP) 0;
435                     }
436
437                     if (addedDump) {
438                         if (addvolumes) {
439                             code = bcdb_AddVolumes(&volumes[0], c);
440                             if (code) {
441                                 if (code < 0)
442                                     addvolumes = 0;
443                                 else {
444                                     ErrorLog(0, 0, code, 0,
445                                              "Warning: Can't add %d volumes to dumpid %u\n",
446                                              c, volumes[0].dump);
447                                 }
448                             }
449                         }
450                         if (!addvolumes) {
451                             for (i = 0; i < c; i++) {
452                                 code = bcdb_AddVolume(&volumes[i]);
453                                 if (code) {
454                                     ErrorLog(0, 0, code, 0,
455                                              "Warning: Can't add volume %s %u to backup database\n",
456                                              volumes[i].name, volumes[i].id);
457                                 }
458                             }
459                         }
460                     }
461                     break;
462
463                 default:
464                     ErrorLog(0, 0, 0, 0,
465                              "Warning: dbWatcher: Unrecognized entry type %d\n",
466                              entryPtr->dlq_type);
467                     break;      /* ignore */
468                 }
469
470             if (entryPtr) {
471                 if (entryPtr->dlq_structPtr)
472                     free(entryPtr->dlq_structPtr);
473                 free(entryPtr);
474             }
475             entryPtr = (dlqlinkP) 0;
476             dumpPtr = (budb_dumpEntry *) 0;
477             volPtr = (budb_volumeEntry *) 0;
478             tapePtr = (budb_tapeEntry *) 0;
479         }                       /*while */
480
481         dbWatcherinprogress = 0;
482 #ifdef AFS_PTHREAD_ENV
483         sleep(2);
484 #else
485         IOMGR_Sleep(2);
486 #endif
487     }
488 }