Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / budb / db_alloc.c
CommitLineData
805e021f
CE
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
25static int nEntries[NBLOCKTYPES];
26static int sizeEntries[NBLOCKTYPES];
27
28afs_int32
29InitDBalloc(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_frag);
40 sizeEntries[volInfo_BLOCK] = sizeof(struct viBlock_info);
41 sizeEntries[tape_BLOCK] = sizeof(struct tBlock_tape);
42 sizeEntries[dump_BLOCK] = sizeof(struct dBlock_dump);
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
55afs_int32
56AllocBlock(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
90afs_int32
91FreeBlock(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
114afs_int32
115AllocStructure(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
212afs_int32
213FreeStructure(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}