]> git.sur5r.net Git - openldap/blob - servers/slapd/zn_malloc.c
c2e8d20f967dbba003601d28367294d9562ec1a4
[openldap] / servers / slapd / zn_malloc.c
1 /* zn_malloc.c - zone-based malloc routines */
2 /* $OpenLDAP$*/
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Copyright 2004 IBM Corporation
17  * All rights reserved.
18  * Redisribution and use in source and binary forms, with or without
19  * modification, are permitted only as  authorizd by the OpenLADP
20  * Public License.
21  */
22 /* ACKNOWLEDGEMENTS
23  * This work originally developed by Jong-Hyuk Choi
24  * 2004/12/09   jongchoi@OpenLDAP.org
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30 #include <ac/string.h>
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <fcntl.h>
34
35 #include "slap.h"
36
37 #ifdef SLAP_ZONE_ALLOC
38
39 static int slap_zone_cmp(const void *v1, const void *v2);
40 void * slap_replenish_zopool(void *ctx);
41
42 static void
43 slap_zo_release(void *data)
44 {
45         struct zone_object *zo = (struct zone_object *)data;
46         ch_free( zo );
47 }
48
49 void
50 slap_zn_mem_destroy(
51         void *ctx
52 )
53 {
54         struct zone_heap *zh = ctx;
55         int pad = 2*sizeof(int)-1, pad_shift;
56         int order_start = -1, i, j;
57         struct zone_object *zo;
58
59         pad_shift = pad - 1;
60         do {
61                 order_start++;
62         } while (pad_shift >>= 1);
63
64         ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
65         for (i = 0; i < zh->zh_zoneorder - order_start + 1; i++) {
66                 zo = LDAP_LIST_FIRST(&zh->zh_free[i]);
67                 while (zo) {
68                         struct zone_object *zo_tmp = zo;
69                         zo = LDAP_LIST_NEXT(zo, zo_link);
70                         LDAP_LIST_REMOVE(zo_tmp, zo_link);
71                         LDAP_LIST_INSERT_HEAD(&zh->zh_zopool, zo_tmp, zo_link);
72                 }
73         }
74         ch_free(zh->zh_free);
75
76         for (i = 0; i < zh->zh_numzones; i++) {
77                 for (j = 0; j < zh->zh_zoneorder - order_start + 1; j++) {
78                         ch_free(zh->zh_maps[i][j]);
79                 }
80                 ch_free(zh->zh_maps[i]);
81                 munmap(zh->zh_zones[i], zh->zh_zonesize);
82                 ldap_pvt_thread_rdwr_destroy(&zh->zh_znlock[i]);
83         }
84         ch_free(zh->zh_maps);
85         ch_free(zh->zh_zones);
86         ch_free(zh->zh_seqno);
87         ch_free(zh->zh_znlock);
88
89         avl_free(zh->zh_zonetree, slap_zo_release);
90
91         zo = LDAP_LIST_FIRST(&zh->zh_zopool);
92         while (zo) {
93                 struct zone_object *zo_tmp = zo;
94                 zo = LDAP_LIST_NEXT(zo, zo_link);
95                 if (!zo_tmp->zo_blockhead) {
96                         LDAP_LIST_REMOVE(zo_tmp, zo_link);
97                 }
98         }
99         zo = LDAP_LIST_FIRST(&zh->zh_zopool);
100         while (zo) {
101                 struct zone_object *zo_tmp = zo;
102                 zo = LDAP_LIST_NEXT(zo, zo_link);
103                 ch_free(zo_tmp);
104         }
105         ldap_pvt_thread_mutex_unlock(&zh->zh_mutex);
106         ldap_pvt_thread_rdwr_destroy(&zh->zh_lock);
107         ldap_pvt_thread_mutex_destroy(&zh->zh_mutex);
108         ch_free(zh);
109 }
110
111 void *
112 slap_zn_mem_create(
113         ber_len_t initsize,
114         ber_len_t maxsize,
115         ber_len_t deltasize,
116         ber_len_t zonesize
117 )
118 {
119         struct zone_heap *zh = NULL;
120         ber_len_t zpad;
121         int pad = 2*sizeof(int)-1, pad_shift;
122         int size_shift;
123         int order = -1, order_start = -1, order_end = -1;
124         int i, j;
125         struct zone_object *zo;
126
127         Debug(LDAP_DEBUG_NONE,
128                 "--> slap_zn_mem_create: initsize=%d, maxsize=%d\n",
129                 initsize, maxsize, 0);
130         Debug(LDAP_DEBUG_NONE,
131                 "++> slap_zn_mem_create: deltasize=%d, zonesize=%d\n",
132                 deltasize, zonesize, 0);
133
134         zh = (struct zone_heap *)ch_calloc(1, sizeof(struct zone_heap));
135
136         zh->zh_fd = open("/dev/zero", O_RDWR);
137
138         if ( zonesize ) {
139                 zh->zh_zonesize = zonesize;
140         } else {
141                 zh->zh_zonesize = SLAP_ZONE_SIZE;
142         }
143
144         zpad = zh->zh_zonesize - 1;
145         zh->zh_numzones = ((initsize + zpad) & ~zpad) / zh->zh_zonesize;
146
147         if ( maxsize && maxsize >= initsize ) {
148                 zh->zh_maxzones = ((maxsize + zpad) & ~zpad) / zh->zh_zonesize;
149         } else {
150                 zh->zh_maxzones = ((initsize + zpad) & ~zpad) / zh->zh_zonesize;
151         }
152
153         if ( deltasize ) {
154                 zh->zh_deltazones = ((deltasize + zpad) & ~zpad) / zh->zh_zonesize;
155         } else {
156                 zh->zh_deltazones = ((SLAP_ZONE_DELTA+zpad) & ~zpad) / zh->zh_zonesize;
157         }
158
159         size_shift = zh->zh_zonesize - 1;
160         do {
161                 order_end++;
162         } while (size_shift >>= 1);
163
164         pad_shift = pad - 1;
165         do {
166                 order_start++;
167         } while (pad_shift >>= 1);
168
169         order = order_end - order_start + 1;
170
171         zh->zh_zones = (void **)ch_malloc(zh->zh_maxzones * sizeof(void*));
172         zh->zh_znlock = (ldap_pvt_thread_rdwr_t *)ch_malloc(
173                                                 zh->zh_maxzones * sizeof(ldap_pvt_thread_rdwr_t *));
174         zh->zh_maps = (unsigned char ***)ch_malloc(
175                                         zh->zh_maxzones * sizeof(unsigned char**));
176
177         zh->zh_zoneorder = order_end;
178         zh->zh_free = (struct zh_freelist *)
179                                         ch_malloc(order * sizeof(struct zh_freelist));
180         zh->zh_seqno = (unsigned long *)ch_calloc(zh->zh_maxzones,
181                                                                                         sizeof(unsigned long));
182         for (i = 0; i < order; i++) {
183                 LDAP_LIST_INIT(&zh->zh_free[i]);
184         }
185         LDAP_LIST_INIT(&zh->zh_zopool);
186
187         for (i = 0; i < zh->zh_numzones; i++) {
188                 zh->zh_zones[i] = mmap(0, zh->zh_zonesize, PROT_READ | PROT_WRITE,
189                                                         MAP_PRIVATE, zh->zh_fd, 0);
190                 zh->zh_maps[i] = (unsigned char **)
191                                         ch_malloc(order * sizeof(unsigned char *));
192                 for (j = 0; j < order; j++) {
193                         int shiftamt = order_start + 1 + j;
194                         int nummaps = zh->zh_zonesize >> shiftamt;
195                         assert(nummaps);
196                         nummaps >>= 3;
197                         if (!nummaps) nummaps = 1;
198                         zh->zh_maps[i][j] = (unsigned char *)ch_malloc(nummaps);
199                         memset(zh->zh_maps[i][j], 0, nummaps);
200                 }
201
202                 if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
203                         slap_replenish_zopool(zh);
204                 }
205                 zo = LDAP_LIST_FIRST(&zh->zh_zopool);
206                 LDAP_LIST_REMOVE(zo, zo_link);
207                 zo->zo_ptr = zh->zh_zones[i];
208                 zo->zo_idx = i;
209                 LDAP_LIST_INSERT_HEAD(&zh->zh_free[order-1], zo, zo_link);
210
211                 if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
212                         slap_replenish_zopool(zh);
213                 }
214                 zo = LDAP_LIST_FIRST(&zh->zh_zopool);
215                 LDAP_LIST_REMOVE(zo, zo_link);
216                 zo->zo_ptr = zh->zh_zones[i];
217                 zo->zo_siz = zh->zh_zonesize;
218                 zo->zo_idx = i;
219                 avl_insert(&zh->zh_zonetree, zo, slap_zone_cmp, avl_dup_error);
220                 ldap_pvt_thread_rdwr_init(&zh->zh_znlock[i]);
221         }
222
223         ldap_pvt_thread_mutex_init(&zh->zh_mutex);
224         ldap_pvt_thread_rdwr_init(&zh->zh_lock);
225
226         return zh;
227 }
228
229 void *
230 slap_zn_malloc(
231     ber_len_t   size,
232         void *ctx
233 )
234 {
235         struct zone_heap *zh = ctx;
236         ber_len_t size_shift;
237         int pad = 2*sizeof(int)-1, pad_shift;
238         int order = -1, order_start = -1;
239         struct zone_object *zo, *zo_new, *zo_left, *zo_right;
240         ber_len_t *ptr, *new;
241         int idx;
242         unsigned long diff;
243         int i, j, k;
244
245         Debug(LDAP_DEBUG_NONE,
246                 "--> slap_zn_malloc: size=%d\n", size, 0, 0);
247
248         if (!zh) return ber_memalloc_x(size, NULL);
249
250         /* round up to doubleword boundary */
251         size += 2*sizeof(ber_len_t) + pad;
252         size &= ~pad;
253
254         size_shift = size - 1;
255         do {
256                 order++;
257         } while (size_shift >>= 1);
258
259         pad_shift = pad - 1;
260         do {
261                 order_start++;
262         } while (pad_shift >>= 1);
263
264 retry:
265
266         ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
267         for (i = order; i <= zh->zh_zoneorder &&
268                         LDAP_LIST_EMPTY(&zh->zh_free[i-order_start]); i++);
269
270         if (i == order) {
271                 zo_new = LDAP_LIST_FIRST(&zh->zh_free[i-order_start]);
272                 LDAP_LIST_REMOVE(zo_new, zo_link);
273                 ptr = zo_new->zo_ptr;
274                 idx = zo_new->zo_idx;
275                 diff = (unsigned long)((char*)ptr -
276                                 (char*)zh->zh_zones[idx]) >> (order + 1);
277                 zh->zh_maps[idx][order-order_start][diff>>3] |= (1 << (diff & 0x7));
278                 *ptr++ = zh->zh_seqno[idx];
279                 *ptr++ = size - 2*sizeof(ber_len_t);
280                 zo_new->zo_ptr = NULL;
281                 zo_new->zo_idx = -1;
282                 LDAP_LIST_INSERT_HEAD(&zh->zh_zopool, zo_new, zo_link);
283                 ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
284                 Debug(LDAP_DEBUG_NONE, "slap_zn_malloc: returning 0x%x, 0x%x\n",
285                                 ptr, (int)ptr>>(zh->zh_zoneorder+1), 0);
286                 return((void*)ptr);
287         } else if (i <= zh->zh_zoneorder) {
288                 for (j = i; j > order; j--) {
289                         zo_left = LDAP_LIST_FIRST(&zh->zh_free[j-order_start]);
290                         LDAP_LIST_REMOVE(zo_left, zo_link);
291                         if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
292                                 slap_replenish_zopool(zh);
293                         }
294                         zo_right = LDAP_LIST_FIRST(&zh->zh_zopool);
295                         LDAP_LIST_REMOVE(zo_right, zo_link);
296                         zo_right->zo_ptr = zo_left->zo_ptr + (1 << j);
297                         zo_right->zo_idx = zo_left->zo_idx;
298                         Debug(LDAP_DEBUG_NONE,
299                                 "slap_zn_malloc: split (left=0x%x, right=0x%x)\n",
300                                 zo_left->zo_ptr, zo_right->zo_ptr, 0);
301                         if (j == order + 1) {
302                                 ptr = zo_left->zo_ptr;
303                                 diff = (unsigned long)((char*)ptr -
304                                                 (char*)zh->zh_zones[zo_left->zo_idx]) >> (order+1);
305                                 zh->zh_maps[zo_left->zo_idx][order-order_start][diff>>3] |=
306                                                 (1 << (diff & 0x7));
307                                 *ptr++ = zh->zh_seqno[zo_left->zo_idx];
308                                 *ptr++ = size - 2*sizeof(ber_len_t);
309                                 LDAP_LIST_INSERT_HEAD(
310                                                 &zh->zh_free[j-1-order_start], zo_right, zo_link);
311                                 LDAP_LIST_INSERT_HEAD(&zh->zh_zopool, zo_left, zo_link);
312                                 ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
313                                 Debug(LDAP_DEBUG_NONE,
314                                         "slap_zn_malloc: returning 0x%x, 0x%x\n",
315                                         ptr, (int)ptr>>(zh->zh_zoneorder+1), 0);
316                                 return((void*)ptr);
317                         } else {
318                                 LDAP_LIST_INSERT_HEAD(
319                                                 &zh->zh_free[j-1-order_start], zo_right, zo_link);
320                                 LDAP_LIST_INSERT_HEAD(
321                                                 &zh->zh_free[j-1-order_start], zo_left, zo_link);
322                         }
323                 }
324                 assert(0);
325         } else {
326
327                 if ( zh->zh_maxzones < zh->zh_numzones + zh->zh_deltazones ) {
328                         ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
329                         Debug( LDAP_DEBUG_TRACE,
330                                 "slap_zn_malloc of %lu bytes failed, using ch_malloc\n",
331                                 (long)size, 0, 0);
332                         Debug(LDAP_DEBUG_NONE,
333                                 "slap_zn_malloc: returning 0x%x, 0x%x\n",
334                                 ptr, (int)ptr>>(zh->zh_zoneorder+1), 0);
335                         return (void*)ch_malloc(size);
336                 }
337
338                 for (i = zh->zh_numzones; i < zh->zh_numzones+zh->zh_deltazones; i++) {
339                         zh->zh_zones[i] = mmap(0, zh->zh_zonesize, PROT_READ | PROT_WRITE,
340                                                                 MAP_PRIVATE, zh->zh_fd, 0);
341                         zh->zh_maps[i] = (unsigned char **)
342                                                 ch_malloc((zh->zh_zoneorder - order_start + 1) *
343                                                 sizeof(unsigned char *));
344                         for (j = 0; j < zh->zh_zoneorder-order_start+1; j++) {
345                                 int shiftamt = order_start + 1 + j;
346                                 int nummaps = zh->zh_zonesize >> shiftamt;
347                                 assert(nummaps);
348                                 nummaps >>= 3;
349                                 if (!nummaps) nummaps = 1;
350                                 zh->zh_maps[i][j] = (unsigned char *)ch_malloc(nummaps);
351                                 memset(zh->zh_maps[i][j], 0, nummaps);
352                         }
353         
354                         if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
355                                 slap_replenish_zopool(zh);
356                         }
357                         zo = LDAP_LIST_FIRST(&zh->zh_zopool);
358                         LDAP_LIST_REMOVE(zo, zo_link);
359                         zo->zo_ptr = zh->zh_zones[i];
360                         zo->zo_idx = i;
361                         LDAP_LIST_INSERT_HEAD(&zh->
362                                                 zh_free[zh->zh_zoneorder-order_start],zo,zo_link);
363         
364                         if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
365                                 slap_replenish_zopool(zh);
366                         }
367                         zo = LDAP_LIST_FIRST(&zh->zh_zopool);
368                         LDAP_LIST_REMOVE(zo, zo_link);
369                         zo->zo_ptr = zh->zh_zones[i];
370                         zo->zo_siz = zh->zh_zonesize;
371                         zo->zo_idx = i;
372                         avl_insert(&zh->zh_zonetree, zo, slap_zone_cmp, avl_dup_error);
373                         ldap_pvt_thread_rdwr_init(&zh->zh_znlock[i]);
374                 }
375                 zh->zh_numzones += zh->zh_deltazones;
376                 ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
377                 goto retry;
378         }
379 }
380
381 void *
382 slap_zn_calloc( ber_len_t n, ber_len_t size, void *ctx )
383 {
384         void *new;
385
386         new = slap_zn_malloc( n*size, ctx );
387         if ( new ) {
388                 memset( new, 0, n*size );
389         }
390         return new;
391 }
392
393 void *
394 slap_zn_realloc(void *ptr, ber_len_t size, void *ctx)
395 {
396         struct zone_heap *zh = ctx;
397         int pad = 2*sizeof(int)-1, pad_shift;
398         int order_start = -1, order = -1;
399         struct zone_object zoi, *zoo;
400         ber_len_t *p = (ber_len_t *)ptr, *new;
401         unsigned long diff;
402         int i;
403         void *newptr = NULL;
404         struct zone_heap *zone = NULL;
405
406         Debug(LDAP_DEBUG_NONE,
407                 "--> slap_zn_realloc: ptr=0x%x, size=%d\n", ptr, size, 0);
408
409         if (ptr == NULL)
410                 return slap_zn_malloc(size, zh);
411
412         zoi.zo_ptr = p;
413         zoi.zo_idx = -1;
414
415         if (zh) {
416                 ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
417                 zoo = avl_find(zh->zh_zonetree, &zoi, slap_zone_cmp);
418                 ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
419         }
420
421         /* Not our memory? */
422         if (!zoo) {
423                 /* duplicate of realloc behavior, oh well */
424                 new = ber_memrealloc_x(ptr, size, NULL);
425                 if (new) {
426                         return new;
427                 }
428                 Debug(LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n",
429                                 (long) size, 0, 0);
430                 assert(0);
431                 exit( EXIT_FAILURE );
432         }
433
434         assert(zoo->zo_idx != -1);      
435
436         zone = zh->zh_zones[zoo->zo_idx];
437
438         if (size == 0) {
439                 slap_zn_free(ptr, zh);
440                 return NULL;
441         }
442
443         newptr = slap_zn_malloc(size, zh);
444         if (size < p[-1]) {
445                 AC_MEMCPY(newptr, ptr, size);
446         } else {
447                 AC_MEMCPY(newptr, ptr, p[-1]);
448         }
449         slap_zn_free(ptr, zh);
450         return newptr;
451 }
452
453 void
454 slap_zn_free(void *ptr, void *ctx)
455 {
456         struct zone_heap *zh = ctx;
457         int size, size_shift, order_size;
458         int pad = 2*sizeof(int)-1, pad_shift;
459         ber_len_t *p = (ber_len_t *)ptr, *tmpp;
460         int order_start = -1, order = -1;
461         struct zone_object zoi, *zoo, *zo;
462         unsigned long diff;
463         int i, k, inserted = 0, idx;
464         struct zone_heap *zone = NULL;
465
466         zoi.zo_ptr = p;
467         zoi.zo_idx = -1;
468
469         Debug(LDAP_DEBUG_NONE, "--> slap_zn_free: ptr=0x%x\n", ptr, 0, 0);
470
471         if (zh) {
472                 ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
473                 zoo = avl_find(zh->zh_zonetree, &zoi, slap_zone_cmp);
474                 ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
475         }
476
477         if (!zoo) {
478                 ber_memfree_x(ptr, NULL);
479         } else {
480                 idx = zoo->zo_idx;
481                 assert(idx != -1);
482                 zone = zh->zh_zones[idx];
483
484                 size = *(--p);
485                 size_shift = size + 2*sizeof(ber_len_t) - 1;
486                 do {
487                         order++;
488                 } while (size_shift >>= 1);
489
490                 pad_shift = pad - 1;
491                 do {
492                         order_start++;
493                 } while (pad_shift >>= 1);
494
495                 ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
496                 for (i = order, tmpp = p; i <= zh->zh_zoneorder; i++) {
497                         order_size = 1 << (i+1);
498                         diff = (unsigned long)((char*)tmpp - (char*)zone) >> (i+1);
499                         zh->zh_maps[idx][i-order_start][diff>>3] &= (~(1 << (diff & 0x7)));
500                         if (diff == ((diff>>1)<<1)) {
501                                 if (!(zh->zh_maps[idx][i-order_start][(diff+1)>>3] &
502                                                 (1<<((diff+1)&0x7)))) {
503                                         zo = LDAP_LIST_FIRST(&zh->zh_free[i-order_start]);
504                                         while (zo) {
505                                                 if ((char*)zo->zo_ptr == (char*)tmpp) {
506                                                         LDAP_LIST_REMOVE( zo, zo_link );
507                                                 } else if ((char*)zo->zo_ptr ==
508                                                                 (char*)tmpp + order_size) {
509                                                         LDAP_LIST_REMOVE(zo, zo_link);
510                                                         break;
511                                                 }
512                                                 zo = LDAP_LIST_NEXT(zo, zo_link);
513                                         }
514                                         if (zo) {
515                                                 if (i < zh->zh_zoneorder) {
516                                                         inserted = 1;
517                                                         zo->zo_ptr = tmpp;
518                                                         Debug(LDAP_DEBUG_NONE,
519                                                                 "slap_zn_free: merging 0x%x\n",
520                                                                 zo->zo_ptr, 0, 0);
521                                                         LDAP_LIST_INSERT_HEAD(&zh->zh_free[i-order_start+1],
522                                                                         zo, zo_link);
523                                                 }
524                                                 continue;
525                                         } else {
526                                                 if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
527                                                         slap_replenish_zopool(zh);
528                                                 }
529                                                 zo = LDAP_LIST_FIRST(&zh->zh_zopool);
530                                                 LDAP_LIST_REMOVE(zo, zo_link);
531                                                 zo->zo_ptr = tmpp;
532                                                 zo->zo_idx = idx;
533                                                 Debug(LDAP_DEBUG_NONE,
534                                                         "slap_zn_free: merging 0x%x\n",
535                                                         zo->zo_ptr, 0, 0);
536                                                 LDAP_LIST_INSERT_HEAD(&zh->zh_free[i-order_start],
537                                                                 zo, zo_link);
538                                                 break;
539
540                                                 Debug(LDAP_DEBUG_ANY, "slap_zn_free: "
541                                                         "free object not found while bit is clear.\n",
542                                                         0, 0, 0);
543                                                 assert(zo);
544
545                                         }
546                                 } else {
547                                         if (!inserted) {
548                                                 if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
549                                                         slap_replenish_zopool(zh);
550                                                 }
551                                                 zo = LDAP_LIST_FIRST(&zh->zh_zopool);
552                                                 LDAP_LIST_REMOVE(zo, zo_link);
553                                                 zo->zo_ptr = tmpp;
554                                                 zo->zo_idx = idx;
555                                                 Debug(LDAP_DEBUG_NONE,
556                                                         "slap_zn_free: merging 0x%x\n",
557                                                         zo->zo_ptr, 0, 0);
558                                                 LDAP_LIST_INSERT_HEAD(&zh->zh_free[i-order_start],
559                                                                 zo, zo_link);
560                                         }
561                                         break;
562                                 }
563                         } else {
564                                 if (!(zh->zh_maps[idx][i-order_start][(diff-1)>>3] &
565                                                 (1<<((diff-1)&0x7)))) {
566                                         zo = LDAP_LIST_FIRST(&zh->zh_free[i-order_start]);
567                                         while (zo) {
568                                                 if ((char*)zo->zo_ptr == (char*)tmpp) {
569                                                         LDAP_LIST_REMOVE(zo, zo_link);
570                                                 } else if ((char*)tmpp == zo->zo_ptr + order_size) {
571                                                         LDAP_LIST_REMOVE(zo, zo_link);
572                                                         tmpp = zo->zo_ptr;
573                                                         break;
574                                                 }
575                                                 zo = LDAP_LIST_NEXT(zo, zo_link);
576                                         }
577                                         if (zo) {
578                                                 if (i < zh->zh_zoneorder) {
579                                                         inserted = 1;
580                                                         Debug(LDAP_DEBUG_NONE,
581                                                                 "slap_zn_free: merging 0x%x\n",
582                                                                 zo->zo_ptr, 0, 0);
583                                                         LDAP_LIST_INSERT_HEAD(&zh->zh_free[i-order_start+1],
584                                                                         zo, zo_link);
585                                                         continue;
586                                                 }
587                                         } else {
588                                                 if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
589                                                         slap_replenish_zopool(zh);
590                                                 }
591                                                 zo = LDAP_LIST_FIRST(&zh->zh_zopool);
592                                                 LDAP_LIST_REMOVE(zo, zo_link);
593                                                 zo->zo_ptr = tmpp;
594                                                 zo->zo_idx = idx;
595                                                 Debug(LDAP_DEBUG_NONE,
596                                                         "slap_zn_free: merging 0x%x\n",
597                                                         zo->zo_ptr, 0, 0);
598                                                 LDAP_LIST_INSERT_HEAD(&zh->zh_free[i-order_start],
599                                                                 zo, zo_link);
600                                                 break;
601
602                                                 Debug(LDAP_DEBUG_ANY, "slap_zn_free: "
603                                                         "free object not found while bit is clear.\n",
604                                                         0, 0, 0 );
605                                                 assert( zo );
606
607                                         }
608                                 } else {
609                                         if ( !inserted ) {
610                                                 if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
611                                                         slap_replenish_zopool(zh);
612                                                 }
613                                                 zo = LDAP_LIST_FIRST(&zh->zh_zopool);
614                                                 LDAP_LIST_REMOVE(zo, zo_link);
615                                                 zo->zo_ptr = tmpp;
616                                                 zo->zo_idx = idx;
617                                                 Debug(LDAP_DEBUG_NONE,
618                                                         "slap_zn_free: merging 0x%x\n",
619                                                         zo->zo_ptr, 0, 0);
620                                                 LDAP_LIST_INSERT_HEAD(&zh->zh_free[i-order_start],
621                                                                 zo, zo_link);
622                                         }
623                                         break;
624                                 }
625                         }
626                 }
627                 ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
628         }
629 }
630
631 static int
632 slap_zone_cmp(const void *v1, const void *v2)
633 {
634         const struct zone_object *zo1 = v1;
635         const struct zone_object *zo2 = v2;
636         char *ptr1;
637         char *ptr2;
638         ber_len_t zpad;
639
640         zpad = zo2->zo_siz - 1;
641         ptr1 = (char*)(((unsigned long)zo1->zo_ptr + zpad) & ~zpad);
642         ptr2 = (char*)zo2->zo_ptr + ((char*)ptr1 - (char*)zo1->zo_ptr);
643         ptr2 = (char*)(((unsigned long)ptr2 + zpad) & ~zpad);
644         return (int)((char*)ptr1 - (char*)ptr2);
645 }
646
647 void *
648 slap_replenish_zopool(
649         void *ctx
650 )
651 {
652         struct zone_heap* zh = ctx;
653         struct zone_object *zo_block;
654         int i;
655
656         zo_block = (struct zone_object *)ch_malloc(
657                                         SLAP_ZONE_ZOBLOCK * sizeof(struct zone_object));
658
659         if ( zo_block == NULL ) {
660                 return NULL;
661         }
662
663         zo_block[0].zo_blockhead = 1;
664         LDAP_LIST_INSERT_HEAD(&zh->zh_zopool, &zo_block[0], zo_link);
665         for (i = 1; i < SLAP_ZONE_ZOBLOCK; i++) {
666                 zo_block[i].zo_blockhead = 0;
667                 LDAP_LIST_INSERT_HEAD(&zh->zh_zopool, &zo_block[i], zo_link );
668         }
669
670         return zo_block;
671 }
672
673 int
674 slap_zn_invalidate(
675         void *ctx,
676         void *ptr
677 )
678 {
679         struct zone_heap* zh = ctx;
680         struct zone_object zoi, *zoo;
681         struct zone_heap *zone = NULL;
682         int seqno = *((ber_len_t*)ptr - 2);
683         int idx = -1, rc = 0;
684         int pad = 2*sizeof(int)-1, pad_shift;
685         int order_start = -1, i;
686         struct zone_object *zo;
687
688         pad_shift = pad - 1;
689         do {
690                 order_start++;
691         } while (pad_shift >>= 1);
692
693         zoi.zo_ptr = ptr;
694         zoi.zo_idx = -1;
695
696         ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
697         zoo = avl_find(zh->zh_zonetree, &zoi, slap_zone_cmp);
698
699         if (zoo) {
700                 idx = zoo->zo_idx;
701                 assert(idx != -1);
702                 madvise(zh->zh_zones[idx], zh->zh_zonesize, MADV_DONTNEED);
703                 for (i = 0; i < zh->zh_zoneorder - order_start + 1; i++) {
704                         int shiftamt = order_start + 1 + i;
705                         int nummaps = zh->zh_zonesize >> shiftamt;
706                         assert(nummaps);
707                         nummaps >>= 3;
708                         if (!nummaps) nummaps = 1;
709                         memset(zh->zh_maps[idx][i], 0, nummaps);
710                         zo = LDAP_LIST_FIRST(&zh->zh_free[i]);
711                         while (zo) {
712                                 struct zone_object *zo_tmp = zo;
713                                 zo = LDAP_LIST_NEXT(zo, zo_link);
714                                 if (zo_tmp && zo_tmp->zo_idx == idx) {
715                                         LDAP_LIST_REMOVE(zo_tmp, zo_link);
716                                         LDAP_LIST_INSERT_HEAD(&zh->zh_zopool, zo_tmp, zo_link);
717                                 }
718                         }
719                 }
720                 if (LDAP_LIST_EMPTY(&zh->zh_zopool)) {
721                         slap_replenish_zopool(zh);
722                 }
723                 zo = LDAP_LIST_FIRST(&zh->zh_zopool);
724                 LDAP_LIST_REMOVE(zo, zo_link);
725                 zo->zo_ptr = zh->zh_zones[idx];
726                 zo->zo_idx = idx;
727                 LDAP_LIST_INSERT_HEAD(&zh->zh_free[zh->zh_zoneorder-order_start],
728                                                                 zo, zo_link);
729                 zh->zh_seqno[idx]++;
730         } else {
731                 Debug(LDAP_DEBUG_NONE, "zone not found for (ctx=0x%x, ptr=0x%x) !\n",
732                                 ctx, ptr, 0);
733         }
734
735         ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
736         Debug(LDAP_DEBUG_NONE, "zone %d invalidate\n", idx, 0, 0);
737         return rc;
738 }
739
740 int
741 slap_zn_validate(
742         void *ctx,
743         void *ptr,
744         int seqno
745 )
746 {
747         struct zone_heap* zh = ctx;
748         struct zone_object zoi, *zoo;
749         struct zone_heap *zone = NULL;
750         int idx, rc = 0;
751
752         zoi.zo_ptr = ptr;
753         zoi.zo_idx = -1;
754
755         zoo = avl_find(zh->zh_zonetree, &zoi, slap_zone_cmp);
756
757         if (zoo) {
758                 idx = zoo->zo_idx;
759                 assert(idx != -1);
760                 assert(seqno <= zh->zh_seqno[idx]);
761                 rc = (seqno == zh->zh_seqno[idx]);
762         }
763
764         return rc;
765 }
766
767 int slap_zh_rlock(
768         void *ctx
769 )
770 {
771         struct zone_heap* zh = ctx;
772         ldap_pvt_thread_rdwr_rlock(&zh->zh_lock);
773 }
774
775 int slap_zh_runlock(
776         void *ctx
777 )
778 {
779         struct zone_heap* zh = ctx;
780         ldap_pvt_thread_rdwr_runlock(&zh->zh_lock);
781 }
782
783 int slap_zh_wlock(
784         void *ctx
785 )
786 {
787         struct zone_heap* zh = ctx;
788         ldap_pvt_thread_rdwr_wlock(&zh->zh_lock);
789 }
790
791 int slap_zh_wunlock(
792         void *ctx
793 )
794 {
795         struct zone_heap* zh = ctx;
796         ldap_pvt_thread_rdwr_wunlock(&zh->zh_lock);
797 }
798
799 int slap_zn_rlock(
800         void *ctx,
801         void *ptr
802 )
803 {
804         struct zone_heap* zh = ctx;
805         struct zone_object zoi, *zoo;
806         struct zone_heap *zone = NULL;
807         int idx;
808
809         zoi.zo_ptr = ptr;
810         zoi.zo_idx = -1;
811
812         ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
813         zoo = avl_find(zh->zh_zonetree, &zoi, slap_zone_cmp);
814         ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
815
816         if (zoo) {
817                 idx = zoo->zo_idx;
818                 assert(idx != -1);
819                 ldap_pvt_thread_rdwr_rlock(&zh->zh_znlock[idx]);
820         }
821 }
822
823 int slap_zn_runlock(
824         void *ctx,
825         void *ptr
826 )
827 {
828         struct zone_heap* zh = ctx;
829         struct zone_object zoi, *zoo;
830         struct zone_heap *zone = NULL;
831         int idx;
832
833         zoi.zo_ptr = ptr;
834         zoi.zo_idx = -1;
835
836         ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
837         zoo = avl_find(zh->zh_zonetree, &zoi, slap_zone_cmp);
838         ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
839
840         if (zoo) {
841                 idx = zoo->zo_idx;
842                 assert(idx != -1);
843                 ldap_pvt_thread_rdwr_runlock(&zh->zh_znlock[idx]);
844         }
845 }
846
847 int slap_zn_wlock(
848         void *ctx,
849         void *ptr
850 )
851 {
852         struct zone_heap* zh = ctx;
853         struct zone_object zoi, *zoo;
854         struct zone_heap *zone = NULL;
855         int idx;
856
857         zoi.zo_ptr = ptr;
858         zoi.zo_idx = -1;
859
860         ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
861         zoo = avl_find(zh->zh_zonetree, &zoi, slap_zone_cmp);
862         ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
863
864         if (zoo) {
865                 idx = zoo->zo_idx;
866                 assert(idx != -1);
867                 ldap_pvt_thread_rdwr_wlock(&zh->zh_znlock[idx]);
868         }
869 }
870
871 int slap_zn_wunlock(
872         void *ctx,
873         void *ptr
874 )
875 {
876         struct zone_heap* zh = ctx;
877         struct zone_object zoi, *zoo;
878         struct zone_heap *zone = NULL;
879         int idx;
880
881         zoi.zo_ptr = ptr;
882         zoi.zo_idx = -1;
883
884         ldap_pvt_thread_mutex_lock( &zh->zh_mutex );
885         zoo = avl_find(zh->zh_zonetree, &zoi, slap_zone_cmp);
886         ldap_pvt_thread_mutex_unlock( &zh->zh_mutex );
887
888         if (zoo) {
889                 idx = zoo->zo_idx;
890                 assert(idx != -1);
891                 ldap_pvt_thread_rdwr_wunlock(&zh->zh_znlock[idx]);
892         }
893 }
894
895 #endif /* SLAP_ZONE_ALLOC */