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