DEVEL15-pthreaded-ubik-20080402
[openafs.git] / src / budb / database.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 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #else
19 #include <netinet/in.h>
20 #endif
21 #include <sys/types.h>
22 #include <afs/stds.h>
23 #include <ubik.h>
24 #include <afs/bubasics.h>
25 #include "budb_errs.h"
26 #include "database.h"
27 #include "error_macros.h"
28 #include "afs/audit.h"
29 #include <string.h>
30
31 int pollCount;
32 struct memoryDB db;             /* really allocate it here */
33
34 void
35 db_panic(reason)
36      char *reason;
37 {
38     LogError(0, "db_panic: %s\n", reason);
39     BUDB_EXIT(-1);
40 }
41
42 afs_int32
43 InitDB()
44 {
45     afs_int32 code;
46
47     pollCount = 0;
48
49     memset(&db, 0, sizeof(db));
50     Lock_Init(&db.lock);
51     if ((code = InitDBalloc()) || (code = InitDBhash()))
52         return code;
53     return 0;
54 }
55
56 /* package up seek and write into one procedure for ease of use */
57
58 /* dbwrite 
59  *      write a portion of the database
60  * entry:
61  *      pos - offset into the database (disk address). If this is in the
62  *              database header, then buff must be a ptr to a portion of
63  *              the in-core header
64  *      buff - the information to write
65  *      len - size of the write
66  */
67
68 afs_int32
69 dbwrite(struct ubik_trans *ut, afs_int32 pos, void *buff, afs_int32 len)
70 {
71     afs_int32 code = 0;
72
73     if (((pos < sizeof(db.h)) && (buff != (char *)&db.h + pos))
74         || (pos >= ntohl(db.h.eofPtr))) {
75         Log("dbwrite: Illegal attempt to write at location 0 or past EOF\n");
76         ERROR(BUDB_IO);
77     }
78
79     code = ubik_Seek(ut, 0, pos);
80     if (code) {
81         LogError(code, "dbwrite: ubik_Seek to %d failed\n", pos);
82         ERROR(code);
83     }
84     code = ubik_Write(ut, buff, len);
85     if (code) {
86         LogError(code, "dbwrite: ubik_Write failed\n");
87         ERROR(code);
88     }
89
90   error_exit:
91     if (((++pollCount) % 4) == 0) {     /* Poll every 4 reads/writes */
92 #ifndef AFS_PTHREAD_ENV
93         IOMGR_Poll();
94 #endif
95         pollCount = 0;
96     }
97     return code;
98 }
99
100 /* same thing for read */
101
102 afs_int32
103 dbread(struct ubik_trans *ut, afs_int32 pos, void *buff, afs_int32 len)
104 {
105     afs_int32 code = 0;
106
107     if (pos >= ntohl(db.h.eofPtr)) {
108         LogError(0, "dbread: Attempt to read @%d (past EOF)\n", pos);
109         ERROR(BUDB_IO);
110     }
111
112     code = ubik_Seek(ut, 0, pos);
113     if (code) {
114         LogError(code, "dbread: ubik_Seek to %d failed\n", pos);
115         ERROR(code);
116     }
117     code = ubik_Read(ut, buff, len);
118     if (code) {
119         LogError(code, "dbread: ubik_Read pos %d, buff %d, len %d\n", pos,
120                  buff, len);
121         ERROR(code);
122     }
123
124   error_exit:
125     if (((++pollCount) % 4) == 0) {     /* Poll every 4 reads/writes */
126 #ifndef AFS_PTHREAD_ENV
127         IOMGR_Poll();
128 #endif
129         pollCount = 0;
130     }
131     return code;
132 }
133
134 /* Same as dbread excepts it does checking */
135 afs_int32
136 cdbread(struct ubik_trans *ut, int type, afs_int32 pos, void *buff, afs_int32 len)
137 {
138     afs_int32 code = 0;
139
140     code = checkDiskAddress(pos, type, 0, 0);
141     if (code) {
142         LogError(code, "cdbread: Bad Address for block %d (addr 0x%x)\n",
143                  type, pos);
144         ERROR(code);
145     }
146
147     code = ubik_Seek(ut, 0, pos);
148     if (code) {
149         LogError(code, "cdbread: ubik_Seek to 0x%x failed\n", pos);
150         ERROR(code);
151     }
152     code = ubik_Read(ut, buff, len);
153     if (code) {
154         LogError(code, "cdbread: ubik_Read pos 0x%x, buff %d, len %d\n", pos,
155                  buff, len);
156         ERROR(code);
157     }
158
159   error_exit:
160     if (((++pollCount) % 4) == 0) {     /* Poll every 4 reads/writes */
161 #ifndef AFS_PTHREAD_ENV
162         IOMGR_Poll();
163 #endif
164         pollCount = 0;
165     }
166     return code;
167 }
168
169 /* check that the database has been initialized.  Be careful to fail in a safe
170    manner, to avoid bogusly reinitializing the db.  */
171
172 afs_int32
173 CheckInit(ut, db_init)
174      struct ubik_trans *ut;
175      int (*db_init) ();         /* procedure to call if rebuilding DB */
176 {
177     register afs_int32 code;
178
179     /* Don't read header if not necessary */
180     if (!ubik_CacheUpdate(ut))
181         return 0;
182
183     ObtainWriteLock(&db.lock);
184
185     db.h.eofPtr = htonl(sizeof(db.h));  /* for sanity check in dbread */
186     code = dbread(ut, 0, (char *)&db.h, sizeof(db.h));
187     if (code)
188         ERROR(code);
189
190     if ((ntohl(db.h.version) != BUDB_VERSION)
191         || (ntohl(db.h.checkVersion) != BUDB_VERSION)) {
192
193         if ((ntohl(db.h.version) == 0) || (ntohl(db.h.checkVersion) == 0))
194             ERROR(BUDB_EMPTY);
195
196         LogError(0, "DB version should be %d; Initial = %d; Terminal = %d\n",
197                  BUDB_VERSION, ntohl(db.h.version), ntohl(db.h.checkVersion));
198         ERROR(BUDB_IO);
199     }
200
201     db.readTime = time(0);
202     ht_Reset(&db.volName);
203     ht_Reset(&db.tapeName);
204     ht_Reset(&db.dumpName);
205     ht_Reset(&db.dumpIden);
206
207   error_exit:
208     ReleaseWriteLock(&db.lock);
209     if (code) {
210         if ((code == UEOF) || (code == BUDB_EMPTY)) {
211             if (db_init) {
212                 LogDebug(0, "No data base - Building new one\n");
213
214                 /* try to write a good header */
215                 memset(&db.h, 0, sizeof(db.h));
216                 db.h.version = htonl(BUDB_VERSION);
217                 db.h.checkVersion = htonl(BUDB_VERSION);
218                 db.h.lastUpdate = db.h.lastDumpId = htonl(time(0));
219                 db.h.eofPtr = htonl(sizeof(db.h));
220
221                 /* text ptrs cleared by bzero */
222                 ht_DBInit();
223
224                 code = dbwrite(ut, 0, (char *)&db.h, sizeof(db.h));
225                 if (code)
226                     code = BUDB_IO;     /* return the error code */
227                 else
228                     code = db_init(ut); /* initialize the db */
229             } else {
230                 LogDebug(0, "No data base\n");
231                 code = BUDB_EMPTY;
232             }
233         } else {
234             LogDebug(0, "I/O Error\n");
235             code = BUDB_IO;
236         }
237     }
238     return code;
239 }