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