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