2 Unix SMB/CIFS implementation.
4 very efficient functions to manage mapping a id (such as a fnum) to
5 a pointer. This is used for fnum and search id allocation.
7 Copyright (C) Andrew Tridgell 2004
9 This code is derived from lib/idr.c in the 2.6 Linux kernel, which was
10 written by Jim Houston jim.houston@ccur.com, and is
11 Copyright (C) 2002 by Concurrent Computer Corporation
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 see the section marked "public interface" below for documentation
39 #define IDR_FULL 0xfffffffful
41 #define TOP_LEVEL_FULL (IDR_FULL >> 30)
43 #define IDR_SIZE (1 << IDR_BITS)
44 #define IDR_MASK ((1 << IDR_BITS)-1)
45 #define MAX_ID_SHIFT (sizeof(int)*8 - 1)
46 #define MAX_ID_BIT (1U << MAX_ID_SHIFT)
47 #define MAX_ID_MASK (MAX_ID_BIT - 1)
48 #define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
49 #define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
51 #define set_bit(bit, v) (v) |= (1<<(bit))
52 #define clear_bit(bit, v) (v) &= ~(1<<(bit))
53 #define test_bit(bit, v) ((v) & (1<<(bit)))
57 struct idr_layer *ary[IDR_SIZE];
62 struct idr_layer *top;
63 struct idr_layer *id_free;
68 static struct idr_layer *alloc_layer(struct idr_context *idp)
72 if (!(p = idp->id_free))
74 idp->id_free = p->ary[0];
80 static int find_next_bit(uint32_t bm, int maxid, int n)
82 while (n<maxid && !test_bit(n, bm)) n++;
86 static void free_layer(struct idr_context *idp, struct idr_layer *p)
88 p->ary[0] = idp->id_free;
93 static int idr_pre_get(struct idr_context *idp)
95 while (idp->id_free_cnt < IDR_FREE_MAX) {
96 struct idr_layer *new = talloc_zero(idp, struct idr_layer);
104 static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
107 struct idr_layer *p, *new;
108 struct idr_layer *pa[MAX_LEVEL];
112 memset(pa, 0, sizeof(pa));
120 * We run around this while until we reach the leaf node...
122 n = (id >> (IDR_BITS*l)) & IDR_MASK;
124 m = find_next_bit(bm, IDR_SIZE, n);
126 /* no space available go back to previous layer. */
128 id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
137 id = ((id >> sh) ^ n ^ m) << sh;
139 if ((id >= MAX_ID_BIT) || (id < 0))
144 * Create the layer below if it is missing.
147 if (!(new = alloc_layer(idp)))
156 * We have reached the leaf node, plant the
157 * users pointer and return the raw id.
159 p->ary[m] = (struct idr_layer *)ptr;
160 set_bit(m, p->bitmap);
163 * If this layer is full mark the bit in the layer above
164 * to show that this part of the radix tree is full.
165 * This may complete the layer above and require walking
169 while (p->bitmap == IDR_FULL) {
173 set_bit((n & IDR_MASK), p->bitmap);
178 static int idr_get_new_above_int(struct idr_context *idp, void *ptr, int starting_id)
180 struct idr_layer *p, *new;
188 layers = idp->layers;
190 if (!(p = alloc_layer(idp)))
195 * Add a new layer to the top of the tree if the requested
196 * id is larger than the currently allocated space.
198 while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
202 if (!(new = alloc_layer(idp))) {
204 * The allocation failed. If we built part of
205 * the structure tear it down.
207 for (new = p; p && p != idp->top; new = p) {
210 new->bitmap = new->count = 0;
211 free_layer(idp, new);
217 if (p->bitmap == IDR_FULL)
218 set_bit(0, new->bitmap);
222 idp->layers = layers;
223 v = sub_alloc(idp, ptr, &id);
229 static int sub_remove(struct idr_context *idp, int shift, int id)
231 struct idr_layer *p = idp->top;
232 struct idr_layer **pa[MAX_LEVEL];
233 struct idr_layer ***paa = &pa[0];
239 while ((shift > 0) && p) {
240 n = (id >> shift) & IDR_MASK;
241 clear_bit(n, p->bitmap);
247 if (p != NULL && test_bit(n, p->bitmap)) {
248 clear_bit(n, p->bitmap);
250 while(*paa && ! --((**paa)->count)){
251 free_layer(idp, **paa);
261 static void *_idr_find(struct idr_context *idp, int id)
266 n = idp->layers * IDR_BITS;
269 * This tests to see if bits outside the current tree are
270 * present. If so, tain't one of ours!
272 if ((id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))
275 /* Mask off upper bits we don't use for the search. */
278 while (n >= IDR_BITS && p) {
280 p = p->ary[(id >> n) & IDR_MASK];
285 static int _idr_remove(struct idr_context *idp, int id)
289 /* Mask off upper bits we don't use for the search. */
292 if (sub_remove(idp, (idp->layers - 1) * IDR_BITS, id) == -1) {
296 if ( idp->top && idp->top->count == 1 &&
299 /* We can drop a layer */
300 p = idp->top->ary[0];
301 idp->top->bitmap = idp->top->count = 0;
302 free_layer(idp, idp->top);
306 while (idp->id_free_cnt >= IDR_FREE_MAX) {
307 p = alloc_layer(idp);
313 /************************************************************************
314 this is the public interface
315 **************************************************************************/
318 initialise a idr tree. The context return value must be passed to
319 all subsequent idr calls. To destroy the idr tree use talloc_free()
322 _PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx)
324 return talloc_zero(mem_ctx, struct idr_context);
328 allocate the next available id, and assign 'ptr' into its slot.
329 you can retrieve later this pointer using idr_find()
331 _PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit)
333 int ret = idr_get_new_above_int(idp, ptr, 0);
335 idr_remove(idp, ret);
342 allocate a new id, giving the first available value greater than or
343 equal to the given starting id
345 _PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit)
347 int ret = idr_get_new_above_int(idp, ptr, starting_id);
349 idr_remove(idp, ret);
356 allocate a new id randomly in the given range
358 _PUBLIC_ int idr_get_new_random(struct idr_context *idp, void *ptr, int limit)
362 /* first try a random starting point in the whole range, and if that fails,
363 then start randomly in the bottom half of the range. This can only
364 fail if the range is over half full */
365 id = idr_get_new_above(idp, ptr, 1+(generate_random() % limit), limit);
367 id = idr_get_new_above(idp, ptr, 1+(generate_random()%(limit/2)), limit);
374 find a pointer value previously set with idr_get_new given an id
376 _PUBLIC_ void *idr_find(struct idr_context *idp, int id)
378 return _idr_find(idp, id);
382 remove an id from the idr tree
384 _PUBLIC_ int idr_remove(struct idr_context *idp, int id)
387 ret = _idr_remove((struct idr_context *)idp, id);
389 DEBUG(0,("WARNING: attempt to remove unset id %d in idtree\n", id));