54e1f00c3193ba0f739f93f9b825d4806fd26597
[openafs.git] / src / budb / db_alloc.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 #ifdef AFS_NT40_ENV
16 #include <winsock2.h>
17 #else
18 #include <netinet/in.h>
19 #endif
20 #include <string.h>
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 "budb_internal.h"
28
29 /* block and structure allocation routines */
30
31 static int nEntries[NBLOCKTYPES];
32 static int sizeEntries[NBLOCKTYPES];
33
34 afs_int32
35 InitDBalloc(void)
36 {
37     nEntries[0] = 0;
38     sizeEntries[0] = 0;
39
40     nEntries[volFragment_BLOCK] = NvolFragmentS;
41     nEntries[volInfo_BLOCK] = NvolInfoS;
42     nEntries[tape_BLOCK] = NtapeS;
43     nEntries[dump_BLOCK] = NdumpS;
44
45     sizeEntries[volFragment_BLOCK] = sizeof(((struct vfBlock *) NULL)->a[0]);
46     sizeEntries[volInfo_BLOCK] = sizeof(((struct viBlock *) NULL)->a[0]);
47     sizeEntries[tape_BLOCK] = sizeof(((struct tBlock *) NULL)->a[0]);
48     sizeEntries[dump_BLOCK] = sizeof(((struct dBlock *) NULL)->a[0]);
49
50     return 0;
51 }
52
53 /* AllocBlock
54  *      allocate a (basic) database block. Extends the database if
55  *      no free blocks are available.
56  * exit:
57  *      0 - aP points to a cleared block
58  *      n - error
59  */
60
61 afs_int32
62 AllocBlock(struct ubik_trans *ut,
63            struct block *block, /* copy of data */
64            dbadr *aP)           /* db addr of block */
65 {
66     dbadr a;
67
68     if (db.h.freePtrs[0] == 0) {
69         /* if there are no free blocks, extend the database */
70         LogDebug(2, "AllocBlock: extending db\n");
71
72         a = ntohl(db.h.eofPtr);
73         if (set_header_word(ut, eofPtr, htonl(a + BLOCKSIZE)))
74             return BUDB_IO;
75     } else {
76         a = ntohl(db.h.freePtrs[0]);
77         if (dbread(ut, a, (char *)block, sizeof(block->h))      /* read hdr */
78             ||set_header_word(ut, freePtrs[0], block->h.next)   /* set next */
79             )
80             return BUDB_IO;
81     }
82
83     /* clear and return the block */
84     memset(block, 0, sizeof(*block));
85     *aP = a;
86     return 0;
87 }
88
89 /* FreeBlock
90  *      Free a basic block
91  * entry:
92  *      bh - block header ptr. Memory copy of the block header.
93  *      a - disk address of the block
94  */
95
96 afs_int32
97 FreeBlock(struct ubik_trans *ut,
98           struct blockHeader *bh,       /* copy of data */
99           dbadr a)                      /* db address of block */
100 {
101     if (a != BlockBase(a))
102         db_panic("Block addr no good");
103     memset(bh, 0, sizeof(*bh));
104     bh->next = db.h.freePtrs[0];
105     if (set_header_word(ut, freePtrs[0], htonl(a))
106         || dbwrite(ut, a, (char *)bh, sizeof(*bh)))
107         return BUDB_IO;
108     return 0;
109 }
110
111
112 /* AllocStructure
113  * entry:
114  *      type - type of structure to allocate
115  *      related - address of related block
116  *      saP - db addr of structure
117  *      s -  structure data
118  */
119
120 afs_int32
121 AllocStructure(struct ubik_trans *ut, char type, dbadr related, dbadr *saP, void *s)
122 {
123     dbadr a;                    /* block addr */
124     struct block b;             /* copy of data */
125     int i;                      /* block structure array index */
126     afs_int32 *bs;              /* ptr to first word of structure */
127     int nFree;
128
129     if ((type == 0)
130         || (type > MAX_STRUCTURE_BLOCK_TYPE)
131         ) {
132         db_panic("bad structure type");
133     }
134     bs = (afs_int32 *) b.a;     /* ptr to first structure of block */
135
136     if (db.h.freePtrs[(int) type] == 0) {
137         /* no free items of specified type */
138
139         if (AllocBlock(ut, &b, &a)
140             || set_header_word(ut, freePtrs[(int) type], htonl(a))
141             ) {
142             return BUDB_IO;
143         }
144
145         b.h.next = 0;
146         b.h.type = type;
147         b.h.flags = 0;
148         b.h.nFree = ntohs(nEntries[(int) type] - 1);
149         *bs = 1;                /* not free anymore */
150
151         if (dbwrite(ut, a, (char *)&b, sizeof(b)))
152             return BUDB_IO;
153         LogDebug(2, "AllocStructure: allocated new block\n");
154     } else {
155         int count = 10;
156
157         /* Only do 10 (or so) at a time, to avoid transactions which modify
158          * many buffer.
159          */
160
161         while (1) {
162             a = ntohl(db.h.freePtrs[(int) type]);
163             if (dbread(ut, a, (char *)&b, sizeof(b)))
164                 return BUDB_IO;
165
166             nFree = ntohs(b.h.nFree);
167             if (nFree == 0)
168                 db_panic("nFree is zero");
169
170             /* Completely empty blocks go to generic free list if there are
171              * more blocks on this free list
172              */
173             if (b.h.next && (nFree == nEntries[(int) type]) && (count-- > 0)) {
174                 if (set_header_word(ut, freePtrs[(int) type], b.h.next)
175                     || FreeBlock(ut, &b.h, a)
176                     ) {
177                     return BUDB_IO;
178                 }
179                 LogDebug(2, "AllocStrucure: add to free block list\n");
180             } else {
181                 /* we found a free structure */
182                 if (nFree == 1) {
183                     /* if last free one: unthread block */
184                     if (set_header_word(ut, freePtrs[(int) type], b.h.next))
185                         return BUDB_IO;
186                 }
187                 break;
188             }
189         }
190
191         /* find the free structure - arbitrarily uses first word as
192          * allocated/free status. PA.
193          */
194         i = 0;
195         while (*bs) {
196             i++;
197             bs = (afs_int32 *) ((char *)bs + sizeEntries[(int) type]);
198         }
199
200         if (i >= nEntries[(int) type])
201             db_panic("free count inconsistent with block");
202
203         b.h.nFree = htons(nFree - 1);
204         if (dbwrite(ut, a, (char *)&b, sizeof(b.h)))
205             return BUDB_IO;
206     }
207     *(afs_int32 *) s = 1;       /* make sure structure is not free */
208     *saP = a + ((char *)bs - (char *)&b);
209
210     LogDebug(3, "allocated at %d, block at %d, offset %ld\n", *saP, a,
211              (long int)((char *)bs - (char *)&b));
212     /* caller must write back at least first word of structure */
213     return 0;
214 }
215
216
217
218 afs_int32
219 FreeStructure(struct ubik_trans *ut,
220               char type,                /* type of structure to allocate */
221               dbadr sa)                 /* db addr of structure */
222 {
223     struct blockHeader bh;      /* header of containing block */
224     dbadr a;                    /* db address of block */
225     int nFree;                  /* new free structures count */
226     afs_int32 freeWord;
227
228     if ((type == 0) || (type > MAX_STRUCTURE_BLOCK_TYPE))
229         db_panic("bad structure type");
230
231     a = BlockBase(sa);
232     if (dbread(ut, a, (char *)&bh, sizeof(bh)))
233         return BUDB_IO;
234     if (type != bh.type)
235         db_panic("block and structure of different types");
236
237     bh.nFree = htons(nFree = ntohs(bh.nFree) + 1);
238     if (nFree > nEntries[(int) type])
239         db_panic("free count too large");
240     if (nFree == 1) {           /* add to free list for type */
241         bh.next = db.h.freePtrs[(int) type];
242         if (set_header_word(ut, freePtrs[(int) type], htonl(a)))
243             return BUDB_IO;
244     }
245
246     /* mark the structure as free, and write out block header */
247     if (set_word_offset(ut, sa, &freeWord, 0, 0)
248         || dbwrite(ut, a, (char *)&bh, sizeof(bh)))
249         return BUDB_IO;
250     return 0;
251 }