4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
30 #include <sys/types.h>
35 #include "isns_server.h"
36 #include "isns_cache.h"
37 #include "isns_htab.h"
40 #define UID_REUSABLE(T, X) ((T) - (X)->t >= ONE_DAY)
45 extern int cache_flag
;
48 * ****************************************************************************
50 * search a node from an AVL tree.
52 * tab - the hash table.
53 * uid - the object UID.
54 * return - the node which matches the object UID.
56 * ****************************************************************************
64 htab_itemx_t
*x
= tab
->avlt
;
69 } else if (x
->uid
< uid
) {
80 * ****************************************************************************
82 * search a node from an AVL tree, the object UID of the node
83 * is next to the previous object UID.
85 * tab - the hash table.
86 * uid - the previous object UID.
87 * return - the next node.
89 * ****************************************************************************
97 htab_itemx_t
*p
= NULL
;
98 htab_itemx_t
*x
= tab
->avlt
;
104 } else if (x
->uid
<= uid
) {
113 * ****************************************************************************
115 * perform LL balance rotation on an AVL tree (or the subtree).
117 * a - the left child.
118 * b - the right child.
119 * return - the new root.
121 * ****************************************************************************
123 static htab_itemx_t
*
139 * ****************************************************************************
141 * perform RR balance rotation on an AVL tree (or the subtree).
143 * a - the left child.
144 * b - the right child.
145 * return - the new root.
147 * ****************************************************************************
149 static htab_itemx_t
*
165 * ****************************************************************************
167 * perform LR balance rotation on an AVL tree (or the subtree).
169 * a - the left child.
170 * b - the right child.
171 * return - the new root.
173 * ****************************************************************************
175 static htab_itemx_t
*
185 /* rotate left and then right */
191 /* update balance factor */
215 * ****************************************************************************
217 * perform RL balance rotation on an AVL tree (or the subtree).
219 * a - the left child.
220 * b - the right child.
221 * return - the new root.
223 * ****************************************************************************
225 static htab_itemx_t
*
235 /* rotate right and then left */
241 /* update balance factor */
265 * ****************************************************************************
267 * insert a node into an AVL tree.
269 * tab - the hash table.
270 * x - the node being added.
272 * ****************************************************************************
280 htab_itemx_t
*f
, *a
, *p
, *q
, *b
, *c
;
283 /* initialize the new one */
288 if (tab
->avlt
== NULL
) {
291 /* locate the position */
302 if (x
->uid
< q
->uid
) {
309 if (x
->uid
< q
->uid
) {
314 /* update the balance factor between a to x */
315 if (x
->uid
< a
->uid
) {
324 if (x
->uid
< p
->uid
) {
332 /* brance is not broken */
336 } else if (a
->bf
+ d
== 0) {
340 /* rotate the tree */
345 } else if (b
->bf
== -1) {
353 } else if (b
->bf
== 1) {
358 /* update the parent */
361 } else if (f
->l
== a
) {
363 } else if (f
->r
== a
) {
369 if (x
->uid
> tab
->buid
) {
375 * ****************************************************************************
377 * allocate new node(s) of the avl tree.
379 * tab - the hash table.
380 * uid - the UID of the node.
381 * return - the newly allocated UID node.
383 * ****************************************************************************
385 static htab_itemx_t
*
391 htab_itemx_t
*x
= NULL
;
395 /* overflow happened */
397 /* search for an unused one */
400 avl_search(tab
, uid
) != NULL
) {
404 /* all are used up, sigh! */
409 /* check if there is a gap and the gap needs to be filled up */
410 if (uid
> tab
->buid
&&
411 (tab
->flags
& UID_FLAGS_SEQ
) != 0) {
412 start
= tab
->buid
+ 1;
418 /* make new UID(s) */
421 x
->hval
= BAD_HVAL_MASK
;
423 /* put it to the start of the fifo list */
426 if (tab
->tail
== NULL
) {
430 x
= (htab_itemx_t
*)malloc(sizeof (htab_itemx_t
));
434 /* insert it to the tree */
438 } while (x
!= NULL
&& start
<= end
&& start
!= 0);
444 * ****************************************************************************
446 * insert a new UID node to the avl tree.
448 * tab - the hash table.
449 * uid_p- the pointer of the UID.
450 * hval - the hash value of the new node.
451 * return - 0: no UID value assigned;
452 * 1: assigned an UID.
456 * ****************************************************************************
461 uint32_t *const uid_p
,
467 uint32_t uid
= *uid_p
;
472 /* search the existing one from the tree */
473 x
= avl_search(tab
, uid
);
475 x
= new_uid(tab
, uid
);
476 } else if (!BAD_HVAL(x
->hval
) &&
478 /* the item with this uid will override an */
479 /* existing item, we treat this as an error */
485 /* strip off the used ones */
487 !BAD_HVAL(x
->hval
)) {
494 UID_REUSABLE(tab
->c
->timestamp(), x
) == 0) {
495 /* none is available, make a new one */
497 x
= new_uid(tab
, tab
->buid
+ 1);
503 /* update the available list */
504 if (tab
->list
== NULL
) {
514 return (-1); /* no memory */
518 x
->t
= 0; /* registration initial time */
524 * ****************************************************************************
526 * enlarge the hash table when it gets too full.
528 * tab - the hash table.
530 * ****************************************************************************
539 uint32_t oldsz
, newsz
, mask
;
540 htab_item_t
*item
, *tmp
, **itemp
;
546 /* enlarge the logsize by one */
547 logsize
= tab
->logsize
+ 1;
548 newsz
= (1 << logsize
);
549 items
= (htab_item_t
**)calloc(
550 newsz
* tab
->chunks
, sizeof (htab_item_t
*));
551 /* re-hash all items to the new table */
554 oldsz
= (1 << tab
->logsize
);
556 while (i
< tab
->chunks
) {
559 item
= tab
->items
[(i
* oldsz
) + j
];
560 while (item
!= NULL
) {
562 itemp
= &items
[(i
* newsz
) +
563 (item
->hval
& mask
)];
564 uid
= tab
->c
->get_uid(item
->p
);
565 while (*itemp
!= NULL
&&
566 tab
->c
->get_uid((*itemp
)->p
) >
568 itemp
= &(*itemp
)->next
;
580 tab
->logsize
= logsize
;
583 isnslog(LOG_DEBUG
, "enlarge_htab", "calloc() failed.");
588 * ****************************************************************************
590 * some generic initialization for the hash table.
592 * ****************************************************************************
602 * ****************************************************************************
604 * create a new hash table.
606 * flags - UID_FLAGS_SEQ: the UID in the table needs to be sequential.
607 * logsize - the hash table logsize.
608 * chunks - the number of seperated chunks of the table.
609 * return - the newly created hash table.
611 * ****************************************************************************
621 htab_item_t
**items
= NULL
;
624 /* do not enlarge it if the logsize reaches the maximum */
625 if (logsize
<= MAX_LOGSIZE
&&
627 tab
= (htab_t
*)calloc(1, sizeof (htab_t
));
629 count
= (1 << logsize
);
630 items
= (htab_item_t
**)calloc(
631 count
* chunks
, sizeof (htab_item_t
*));
635 tab
->logsize
= logsize
;
636 tab
->chunks
= chunks
;
637 tab
->mask
= count
- 1;
638 tab
->count
= 1; /* reserve one */
654 * ****************************************************************************
656 * compute a hash value for the specified key.
658 * key - the key of the hash.
659 * return - the hash value.
661 * ****************************************************************************
668 /* use classic Dan Bernstein hash alorigthm */
669 uint32_t hash
= 5381;
672 while ((c
= *key
++) != 0) {
673 hash
= ((hash
<< 5) + hash
) + c
;
680 * ****************************************************************************
682 * add an object to the hash table.
684 * tab - the hash table.
686 * flag - 0: not an association object; otherwise association object.
687 * uid_p- pointer of UID for returning.
688 * update_p - pointer of update flag for returning.
689 * return - error code.
691 * ****************************************************************************
704 htab_item_t
*items
= NULL
, **itemp
;
711 /* compute the hash value */
712 hval
= VALID_HVAL(tab
->c
->get_hval(p
, 0, &flags
));
714 /* check for duplicate */
715 items
= tab
->items
[hval
& tab
->mask
];
716 while (items
!= NULL
) {
717 if (tab
->c
->cmp(items
->p
, p
, 0) == 0) {
719 ec
= tab
->c
->replace_hook(items
->p
, p
, uid_p
,
720 update_p
== NULL
? 1 : 0);
722 if (update_p
!= NULL
) {
732 if (update_p
!= NULL
) {
736 /* make new items for the object */
737 items
= (htab_item_t
*)calloc(tab
->chunks
, sizeof (htab_item_t
));
741 (++tab
->count
) == 0) {
742 /* no memory or table is full */
743 ec
= ISNS_RSP_INTERNAL_ERROR
;
747 /* check if the table needs is too full */
748 chunksz
= (1 << tab
->logsize
);
749 if (tab
->count
>= (chunksz
* HASH_RATIO
) &&
750 tab
->logsize
< MAX_LOGSIZE
) {
752 chunksz
= (1 << tab
->logsize
);
755 /* put the UID of the object to the avl tree */
756 uid
= tab
->c
->get_uid(p
);
757 switch (uid_insert(tab
, &uid
, hval
)) {
759 ec
= ISNS_RSP_INVALID_REGIS
;
762 ec
= ISNS_RSP_INTERNAL_ERROR
;
767 tab
->c
->set_uid(p
, uid
);
773 /* update data store before putting to hash table */
775 /* not association object */
776 ec
= tab
->c
->add_hook(p
);
779 /* put the object to the table */
780 for (i
= 0; ec
== 0; ) {
781 items
[i
].hval
= hval
;
783 itemp
= &tab
->items
[(i
* chunksz
) + (hval
& tab
->mask
)];
784 while (*itemp
!= NULL
&&
785 tab
->c
->get_uid((*itemp
)->p
) > uid
) {
786 itemp
= &(*itemp
)->next
;
788 items
[i
].next
= *itemp
;
791 if (i
< tab
->chunks
) {
792 hval
= VALID_HVAL(tab
->c
->get_hval(p
, i
, &flags
));
798 /* cache has been successfully updated */
801 /* successfully added */
805 /* perform the Default DD behavior */
808 /* set the return uid */
814 if (ec
!= 0 && items
!= NULL
) {
822 * ****************************************************************************
824 * remove an object from the hash table.
826 * tab - the hash table.
827 * p - the lookup control for the object.
828 * uid - the UID of the object.
829 * clone_flag - indicate if the removing is for an association object.
830 * return - the removed object.
832 * ****************************************************************************
844 htab_item_t
*items
= NULL
;
845 htab_item_t
*item
, **itemp
;
846 htab_itemx_t
*x
= NULL
;
852 /* get the object hash value */
854 x
= avl_search(tab
, uid
);
855 if (x
!= NULL
&& !BAD_HVAL(x
->hval
)) {
861 flags
= 0 | FLAGS_CTRL_MASK
;
862 hval
= VALID_HVAL(tab
->c
->get_hval(p
, 0, &flags
));
865 /* search the object from the table */
867 chunksz
= (1 << tab
->logsize
);
869 itemp
= &tab
->items
[(i
* chunksz
) + (hval
& tab
->mask
)];
871 while (item
!= NULL
) {
873 if (tab
->c
->cmp(item
->p
, p
, 1) == 0) {
874 /* make an association object if the object */
875 /* has membership in user-defined DD(s). */
877 if ((clone
= tab
->c
->clone(item
->p
,
878 clone_flag
)) == NULL
) {
879 tab
->c
->ddd(item
->p
, '-');
888 } else if (clone
== item
->p
) {
889 /* itself is an association object */
892 /* replace it with association */
897 /* obj has been removed or updated */
906 if (zhizi
!= NULL
&& i
< tab
->chunks
) {
907 hval
= VALID_HVAL(tab
->c
->get_hval(
914 /* update the node in the avl tree */
917 uid
= tab
->c
->get_uid(zhizi
);
919 x
= avl_search(tab
, uid
);
921 ASSERT(x
!= NULL
&& !BAD_HVAL(x
->hval
));
922 /* mark the uid item as invalid */
923 x
->hval
|= BAD_HVAL_MASK
;
924 /* update the timestamp */
925 x
->t
= tab
->c
->timestamp();
926 /* put it to the end of fifo list */
927 if (tab
->list
!= NULL
) {
944 * ****************************************************************************
946 * lookup an object from the hash table.
948 * tab - the hash table.
949 * p - the lookup control for the item.
950 * uid - the UID of the object.
951 * uid_p- the pointer of UID for returning.
952 * callback - callback function if the object is found.
953 * rekey - flag that indicates if the callback function will update
954 * the key of the object.
955 * return - error code.
957 * ****************************************************************************
965 int (*callback
)(void *, void *),
971 htab_item_t
*item
, **itemp
;
972 htab_itemx_t
*x
= NULL
;
974 uint32_t flags
= 0 | FLAGS_CTRL_MASK
;
978 /* compute the hash value */
980 x
= avl_search(tab
, uid
);
984 hval
= BAD_HVAL_MASK
;
987 hval
= VALID_HVAL(tab
->c
->get_hval(p
, 0, &flags
));
990 /* find the object */
991 if (!BAD_HVAL(hval
)) {
992 i
= flags
& FLAGS_CHUNK_MASK
;
993 chunksz
= (1 << tab
->logsize
);
994 itemp
= &tab
->items
[(i
* chunksz
) + (hval
& tab
->mask
)];
996 while (item
!= NULL
) {
997 if (tab
->c
->cmp(item
->p
, p
, 1) == 0) {
1001 itemp
= &item
->next
;
1007 if (zhizi
!= NULL
) {
1008 /* set the return uid */
1009 if (uid_p
!= NULL
) {
1010 *uid_p
= tab
->c
->get_uid(zhizi
);
1012 /* invoke callback */
1013 if (callback
!= NULL
) {
1014 ret
= callback(zhizi
, p
);
1016 if (rekey
!= 0 && ret
== 0) {
1017 /* Rekey works for one-chunk hash table only. */
1018 ASSERT(tab
->chunks
== 1 && x
!= NULL
);
1019 /* remove from previous slot */
1020 *itemp
= item
->next
;
1021 /* add it to the new slot */
1023 hval
= VALID_HVAL(tab
->c
->get_hval(zhizi
, 0, &flags
));
1026 itemp
= &tab
->items
[(hval
& tab
->mask
)];
1027 while (*itemp
!= NULL
&&
1028 (tab
->c
->get_uid((*itemp
)->p
) >
1029 tab
->c
->get_uid(zhizi
))) {
1030 itemp
= &(*itemp
)->next
;
1032 item
->next
= *itemp
;
1035 } else if (uid_p
!= NULL
) {
1036 /* set the return uid to 0 */
1044 * ****************************************************************************
1046 * get the next object UID from the hash table.
1048 * tab - the hash table.
1049 * uid - the previous objet UID.
1050 * return - the next object UID.
1052 * ****************************************************************************
1063 /* search the next node from the avl tree */
1064 x
= avl_search_next(tab
, uid
);
1067 /* validate the node */
1068 if (!BAD_HVAL(x
->hval
)) {
1072 } while (x
!= NULL
);
1074 /* no more node is available */
1079 * ****************************************************************************
1081 * dump all objects stored in the hash table for debug purpose.
1083 * tab - the hash table.
1085 * ****************************************************************************
1098 chunksz
= (1 << tab
->logsize
);
1100 for (i
= 0; i
< chunksz
; i
++) {
1101 items
= tab
->items
[i
];
1102 while (items
!= NULL
) {
1103 tab
->c
->dump(items
->p
);
1104 items
= items
->next
;