1
/*___INFO__MARK_BEGIN__*/
2
/*************************************************************************
4
* The Contents of this file are made available subject to the terms of
5
* the Sun Industry Standards Source License Version 1.2
7
* Sun Microsystems Inc., March, 2001
10
* Sun Industry Standards Source License Version 1.2
11
* =================================================
12
* The contents of this file are subject to the Sun Industry Standards
13
* Source License Version 1.2 (the "License"); You may not use this file
14
* except in compliance with the License. You may obtain a copy of the
15
* License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
17
* Software provided under this License is provided on an "AS IS" basis,
18
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
19
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
20
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
21
* See the License for the specific provisions governing your rights and
22
* obligations concerning the Software.
24
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
26
* Copyright: 2001 by Sun Microsystems, Inc.
28
* All Rights Reserved.
30
************************************************************************/
31
/*___INFO__MARK_END__*/
36
/* do not compile in monitoring code */
37
#ifndef NO_SGE_COMPILE_DEBUG
38
#define NO_SGE_COMPILE_DEBUG
45
#include "cull_list.h"
46
#include "cull_hash.h"
47
#include "cull_listP.h"
48
#include "cull_multitypeP.h"
49
#include "cull_multitype.h"
50
#include "sge_string.h"
51
#include "sge_hostname.h"
53
/****** cull/hash/--CULL_Hashtable **********************************************
55
* htable -- Hashtable extensions for cull lists
58
* cull_htable cull_hash_create(const lDescr *descr, int size);
60
* void cull_hash_new(lList *lp, int name, bool unique);
62
* void cull_hash_insert(const lListElem *ep, const int pos, );
64
* void cull_hash_remove(const lListElem *ep, const int pos);
66
* void cull_hash_elem(const lListElem *ep);
68
* lListElem *cull_hash_first(const lList *lp, const int pos,
69
* const void *key, const void **iterator);
71
* lListElem *cull_hash_next(const lList *lp, const int pos,
72
* const void *key, const void **iterator);
74
* void cull_hash_free_descr(lDescr *descr);
77
* This module provides an abstraction layer between cull and
78
* the hash table implementation in libuti. It provides the
79
* necessary functions to use hash tables from libuti for cull lists.
81
* The functions defined in this module implement hash tables with
82
* non unique keys, provide wrapper functions for hash insert, remove
83
* and search that are aware of the non unique hash implementation,
84
* functions that deal with the necessary extensions to the cull list
85
* descriptor objects etc.
88
* uti/hash/--Hashtable
89
* cull/hash/cull_hash_create()
90
* cull/hash/cull_hash_new()
91
* cull/hash/cull_hash_insert()
92
* cull/hash/cull_hash_remove()
93
* cull/hash/cull_hash_elem()
94
*******************************************************************************/
96
/****** cull/hash/-CULL_Hashtable_Defines ****************************************************
98
* Defines -- Constants for the cull hash implementation
101
* #define MIN_CULL_HASH_SIZE 4
104
* Provides constants to be used in the hash table implementation
107
* MIN_CULL_HASH_SIZE - minimum size of a hash table. When a new
108
* hash table is created, it will have the size
109
* 2^MIN_CULL_HASH_SIZE
110
*******************************************************************************/
111
#define MIN_CULL_HASH_SIZE 4
113
/****** cull/hash/-CULL_Hashtable_Typedefs ***************************************************
115
* Typedefs -- Typedefs for cull hash implementation
118
* typedef struct _non_unique_hash non_unique_hash;
120
* struct _non_unique_hash {
121
* non_unique_hash *next;
126
* Internal data structure to handle hash tables with non unique
127
* keys. The hash table (from libuti) in this case will not store
128
* a pointer to the cull object itself, but a pointer to a list of
129
* cull objects. This list is implemented using the non_unique_hash
133
* uti/hash/--Hashtable
134
*******************************************************************************/
135
typedef struct _non_unique_hash non_unique_hash;
137
typedef struct non_unique_header {
138
non_unique_hash *first;
139
non_unique_hash *last;
142
struct _non_unique_hash {
143
non_unique_hash *prev;
144
non_unique_hash *next;
148
struct _cull_htable {
149
htable ht; /* hashtable for keys */
150
htable nuht; /* hashtable for lookup of non unique object references */
153
/****** cull/hash/cull_hash_create() *******************************************
155
* cull_hash_create() -- create a new hash table
158
* cull_htable cull_hash_create(const lDescr *descr, int size)
161
* Creates a new hash table for a certain descriptor and returns the
162
* hash description (lHash) for it.
163
* The initial size of the hashtable can be specified.
164
* This allows for optimization of the hashtable, as resize operations
165
* can be minimized when the final hashtable size is known at creation time,
166
* e.g. when copying complete lists.
169
* const lDescr *descr - descriptor for the data field in a
171
* int size - initial size of hashtable will be 2^size
174
* cull_htable - initialized hash description
175
*******************************************************************************/
176
cull_htable cull_hash_create(const lDescr *descr, int size)
178
htable ht = NULL; /* hash table for keys */
179
htable nuht = NULL; /* hash table for non unique access */
180
cull_htable ret = NULL;
182
/* if no size is given, use default value */
184
size = MIN_CULL_HASH_SIZE;
187
/* create hash table for object keys */
188
switch(mt_get_type(descr->mt)) {
190
ht = sge_htable_create(size, dup_func_string,
191
hash_func_string, hash_compare_string);
194
ht = sge_htable_create(size, dup_func_string,
195
hash_func_string, hash_compare_string);
198
ht = sge_htable_create(size, dup_func_u_long32,
199
hash_func_u_long32, hash_compare_u_long32);
202
unknownType("cull_create_hash");
207
/* (optionally) create hash table for non unique hash access */
209
if (!mt_is_unique(descr->mt)) {
210
nuht = sge_htable_create(size, dup_func_pointer,
211
hash_func_pointer, hash_compare_pointer);
213
sge_htable_destroy(ht);
219
/* hashtables OK? Then create cull_htable */
221
ret = (cull_htable)malloc(sizeof(struct _cull_htable));
223
/* malloc error? destroy hashtables */
225
sge_htable_destroy(ht);
227
sge_htable_destroy(nuht);
238
/****** cull/hash/cull_hash_create_hashtables() ********************************
240
* cull_hash_create_hashtables() -- create all hashtables on a list
243
* void cull_hash_create_hashtables(lList *lp)
246
* Creates all hashtables for an empty list.
249
* lList *lp - initialized list structure
252
* If the list already contains elements, these elements are not
253
* inserted into the hash lists.
254
*******************************************************************************/
255
void cull_hash_create_hashtables(lList *lp)
260
lDescr * descr = lp->descr;
262
/* compute final size of hashtables when all elements are inserted */
263
size = hash_compute_size(lGetNumberOfElem(lp));
265
/* create hashtables, pass final size */
266
for(i = 0; descr[i].mt != lEndT; i++) {
267
if(mt_do_hashing(descr[i].mt) && descr[i].ht == NULL) {
268
descr[i].ht = cull_hash_create(&descr[i], size);
272
/* create hash entries for all objects */
279
/****** cull/hash/cull_hash_insert() *******************************************
281
* cull_hash_insert() -- insert a new element in a hash table
284
* void cull_hash_insert(const lListElem *ep, const int pos)
287
* Inserts ep into the hash list for data field at position pos.
288
* A hash key will be computed. The element will be inserted
289
* in the corresponding hash table considering unique/non unique
293
* const lListElem *ep - the cull object to be stored in a hash list
294
* const int pos - describes the data field of the objects that
296
*******************************************************************************/
297
void cull_hash_insert(const lListElem *ep, void *key, cull_htable ht, bool unique)
299
if(ht == NULL || ep == NULL || key == NULL) {
304
sge_htable_store(ht->ht, key, ep);
307
non_unique_header *l;
319
/* do we already have a list of elements with this key? */
320
if(sge_htable_lookup(ht->ht, key, (const void **) &head.p) == True) {
321
/* We only have something to do if ep isn't already stored */
322
if (sge_htable_lookup(ht->nuht, &ep, (const void **)&nuh.p) == False) {
323
nuh.p = (non_unique_hash *)malloc(sizeof(non_unique_hash));
325
nuh.l->prev = head.l->last;
327
nuh.l->prev->next = nuh.p;
328
head.l->last = nuh.p;
329
sge_htable_store(ht->nuht, &ep, nuh.p);
331
} else { /* no list of non unique elements for this key, create new */
332
head.p = (non_unique_header *)malloc(sizeof(non_unique_header));
333
nuh.p = (non_unique_hash *)malloc(sizeof(non_unique_hash));
334
head.l->first = nuh.p;
335
head.l->last = nuh.p;
339
sge_htable_store(ht->ht, key, head.p);
340
sge_htable_store(ht->nuht, &ep, nuh.p);
345
/****** cull/hash/cull_hash_remove() *******************************************
347
* cull_hash_remove() -- remove a cull object from a hash list
350
* void cull_hash_remove(const lListElem *ep, const int pos)
353
* Removes ep from a hash table for data field specified by pos.
356
* const lListElem *ep - the cull object to be removed
357
* const int pos - position of the data field
358
*******************************************************************************/
359
void cull_hash_remove(const lListElem *ep, const int pos)
361
char host_key[CL_MAXHOSTLEN+1];
365
if(ep == NULL || pos < 0) {
369
ht = ep->descr[pos].ht;
376
key = cull_hash_key(ep, pos, host_key);
378
if(mt_is_unique(ep->descr[pos].mt)) {
379
sge_htable_delete(ht->ht, key);
382
non_unique_header *l;
393
/* search element in key hashtable */
394
if(sge_htable_lookup(ht->ht, key, (const void **)&head.p) == True) {
395
/* search element in non unique access hashtable */
396
if (sge_htable_lookup(ht->nuht, &ep, (const void **)&nuh.p) == True) {
397
if (head.l->first == nuh.p) {
398
head.l->first = nuh.l->next;
399
if (head.l->last == nuh.p) {
402
head.l->first->prev = NULL;
404
} else if (head.l->last == nuh.p) {
405
head.l->last = nuh.l->prev;
406
head.l->last->next = NULL;
408
nuh.l->prev->next = nuh.l->next;
409
nuh.l->next->prev = nuh.l->prev;
412
sge_htable_delete(ht->nuht, &ep);
413
free(nuh.p); nuh.p = NULL; /* JG: TODO: use FREE */
415
/* JG: TODO: error output */
418
if (head.l->first == NULL && head.l->last == NULL) {
419
free(head.p); head.p = NULL;
420
sge_htable_delete(ht->ht, key);
427
/****** cull/hash/cull_hash_elem() *********************************************
429
* cull_hash_elem() -- insert cull object into associated hash tables
432
* void cull_hash_elem(const lListElem *ep)
435
* Insert the cull element ep into all hash tables that are
436
* defined for the cull list ep is member of.
439
* const lListElem *ep - the cull object to be hashed
440
*******************************************************************************/
441
void cull_hash_elem(const lListElem *ep) {
444
char host_key[CL_MAXHOSTLEN];
452
for(i = 0; descr[i].mt != lEndT; i++) {
453
if(descr[i].ht != NULL) {
454
cull_hash_insert(ep, cull_hash_key(ep, i, host_key), descr[i].ht,
455
mt_is_unique(descr[i].mt));
460
/****** cull/hash/cull_hash_first() *******************************************
462
* cull_hash_first() -- find first object for a certain key
465
* lListElem* cull_hash_first(const lList *lp, const int pos,
467
* const void **iterator)
470
* Searches for key in the hash table for data field described by
471
* pos in the cull list lp.
472
* If an element is found, it is returned.
473
* If the hash table uses non unique hash keys, iterator returns the
474
* necessary data for consecutive calls of cull_hash_next() returning
475
* objects with the same hash key.
478
* const lList *lp - the cull list to search
479
* const int pos - position of the data field for key
480
* const void *key - the key to use for the search
481
* const void **iterator - iterator for calls of cull_hash_next
484
* lListElem* - first object found matching key,
485
* if no object found: NULL
488
* cull/hash/cull_hash_next()
489
******************************************************************************/
490
lListElem *cull_hash_first(cull_htable ht, const void *key, bool unique,
491
const void **iterator)
499
if (iterator == NULL) {
503
if(ht == NULL || key == NULL) {
510
if (sge_htable_lookup(ht->ht, key, (const void **)&ep.p) == True) {
517
non_unique_header *l;
522
if (sge_htable_lookup(ht->ht, key, (const void **)&head.p) == True) {
523
ep.p = (lListElem *)head.l->first->data;
524
*iterator = head.l->first;
533
/****** cull/hash/cull_hash_next() *********************************************
535
* cull_hash_next() -- find next object matching a key
538
* lListElem* cull_hash_next(const lList *lp, const int pos,
539
* const void *key, const void **iterator)
542
* Returns the next object matching the same key as a previous call
543
* to cull_hash_first or cull_hash_next.
546
* const lList *lp - the cull list to search
547
* const int pos - position of the data field for key
548
* const void *key - the key to use for the search
549
* const void **iterator - iterator to use for the search.
552
* lListElem* - object if found, else NULL
555
* The order in which objects with the same key are returned is not
559
* cull/hash/cull_hash_first()
560
*******************************************************************************/
561
lListElem *cull_hash_next(cull_htable ht, const void **iterator)
563
lListElem *ep = NULL;
564
non_unique_hash *nuh = (non_unique_hash *)*iterator;
572
ep = (lListElem *)nuh->data;
581
/****** cull/hash/cull_hash_delete_non_unique_chain() *************************
583
* cull_hash_delete_non_unique_chain() -- del list of non unique obj.
586
* void cull_hash_delete_non_unique_chain(cull_htable table,
591
* For objects that are stored in a hash table with non unique keys,
592
* for each key a linked list of objects is created.
593
* This function deletes this linked list for each key in the hash
594
* table. It is designed to be called by the function
595
* sge_htable_for_each from the libuti hash implementation.
598
* cull_htable table - hash table in which to delete/free a sublist
599
* const void *key - key of the list to be freed
600
* const void **data - pointer to the sublist
603
* uti/hash/sge_htable_for_each()
604
******************************************************************************/
605
void cull_hash_delete_non_unique_chain(htable table, const void *key,
608
non_unique_header *head = (non_unique_header *)*data;
610
non_unique_hash *nuh = head->first;
612
non_unique_hash *del = nuh;
620
/****** cull/hash/cull_hash_free_descr() **************************************
622
* cull_hash_free_descr() -- free the hash contents of a cull descr
625
* void cull_hash_free_descr(lDescr *descr)
628
* Frees the memory used by the hashing information in a cull
629
* descriptor (lDescr). If a hash table is still associated to
630
* the descriptor, it is also deleted.
633
* lDescr *descr - descriptor to free
636
* cull/hash/cull_hash_delete_non_unique()
637
* uti/hash/sge_htable_destroy()
638
******************************************************************************/
639
void cull_hash_free_descr(lDescr *descr)
642
for(i = 0; descr[i].mt != lEndT; i++) {
643
cull_htable ht = descr[i].ht;
645
if(!mt_is_unique(descr[i].mt)) {
646
/* delete chain of non unique elements */
647
sge_htable_for_each(ht->ht, cull_hash_delete_non_unique_chain);
648
sge_htable_destroy(ht->nuht);
650
sge_htable_destroy(ht->ht);
658
/****** cull/hash/cull_hash_new_check() ****************************************
660
* cull_hash_new() -- create new hash table, if it does not yet exist
663
* int cull_hash_new_check(lList *lp, int nm, bool unique)
666
* Usually hash tables are defined in the object type definition
667
* for each object type in libs/gdi.
669
* There are cases where for a certain application additional hash
670
* tables shall be defined to speed up certain access methods.
672
* cull_hash_new_check can be used to create a hash table for a list
673
* on the contents of a certain field.
674
* If it already exist, nothing is done.
676
* The caller can choose whether the field contents have to be
677
* unique within the list or not.
680
* lList *lp - the list to hold the new hash table
681
* int nm - the field on which to create the hash table
682
* bool unique - unique contents or not
685
* int - 1 on success, else 0
688
* create a non unique hash index on the job owner for a job list
689
* cull_hash_new_check(job_list, JB_owner, false);
692
* cull/hash/cull_hash_new()
694
*******************************************************************************/
695
int cull_hash_new_check(lList *lp, int nm, bool unique)
697
const lDescr *descr = lGetListDescr(lp);
698
int pos = lGetPosInDescr(descr, nm);
700
if (descr != NULL && pos >= 0) {
701
if (descr[pos].ht == NULL) {
702
return cull_hash_new(lp, nm, unique);
709
/****** cull/hash/cull_hash_new() **********************************************
711
* cull_hash_new() -- create new hash table
714
* int cull_hash_new(lList *lp, int nm, int unique)
717
* Usually hash tables are defined in the object type definition
718
* for each object type in libs/gdi.
720
* There are cases where for a certain application additional hash
721
* tables shall be defined to speed up certain access methods.
723
* cull_hash_new can be used to create a hash table for a list
724
* on the contents of a certain field.
725
* The caller can choose whether the field contents have to be
726
* unique within the list or not.
729
* lList *lp - the list to hold the new hash table
730
* int nm - the field on which to create the hash table
731
* bool unique - unique contents or not
734
* int - 1 on success, else 0
737
* create a non unique hash index on the job owner for a job list
738
* cull_hash_new(job_list, JB_owner, 0);
740
*******************************************************************************/
741
int cull_hash_new(lList *lp, int nm, bool unique)
746
char host_key[CL_MAXHOSTLEN];
748
DENTER(CULL_LAYER, "cull_hash_new");
757
pos = lGetPosInDescr(descr, nm);
760
CRITICAL((SGE_EVENT, MSG_CULL_GETELEMSTRERRORXRUNTIMETYPE_S , lNm2Str(nm)));
765
if(descr[pos].ht != NULL) {
766
WARNING((SGE_EVENT, MSG_CULL_HASHTABLEALREADYEXISTS_S, lNm2Str(nm)));
771
/* copy hashing information */
772
descr[pos].mt |= CULL_HASH;
774
descr[pos].mt |= CULL_UNIQUE;
777
size = hash_compute_size(lGetNumberOfElem(lp));
779
descr[pos].ht = cull_hash_create(&descr[pos], size);
781
if (descr[pos].ht == NULL) {
786
/* insert all elements into the new hash table */
788
cull_hash_insert(ep, cull_hash_key(ep, pos, host_key), descr[pos].ht,
796
void *cull_hash_key(const lListElem *ep, int pos, char *host_key)
800
lDescr *descr = &(ep->descr[pos]);
802
switch(mt_get_type(descr->mt)) {
804
key = (void *)&(ep->cont[pos].ul);
808
key = ep->cont[pos].str;
812
if (ep->cont[pos].host != NULL && host_key != NULL) {
813
sge_hostcpy(host_key,ep->cont[pos].host);
814
sge_strtoupper(host_key, CL_MAXHOSTLEN);
820
unknownType("cull_hash_key");
830
cull_hash_statistics(cull_htable ht, dstring *buffer)
832
const char *ret = NULL;
834
sge_dstring_clear(buffer);
837
sge_dstring_copy_string(buffer, "Keys:\n");
838
ret = sge_htable_statistics(ht->ht, buffer);
840
if (ht->nuht != NULL) {
841
sge_dstring_append(buffer, "\nNon Unique Hash Access:\n");
842
ret = sge_htable_statistics(ht->nuht, buffer);
845
ret = sge_dstring_copy_string(buffer, "no hash table");