The __pmHash group of routines implement a generalized suite of linear hashing services based on a key
that is an unsigned int and data that is an opaque pointer to information the caller wishes to associate
with key.
The data type of key makes is suitable for hashed access based on metric identifier (pmID), instance do‐
main number (pmInDom) or internal instance identifiers within an instance domain.
Multiple hash tables may exist, each identified by a hash control struct (__pmHashCtl) hcp which is de‐
clared by the caller and initialized by calling __pmHashInit. Refer to the HASHCONTROL and HASHNODE
sections below for more information on the hash table internal data structures.
The hash table is initially empty but dynamically grows by approximate doubling in size as entries are
added, and this may cause some organizational overhead in relinking the hash chains when the hash table
grows. This overhead can be avoided by optionally calling __pmHashPreAlloc with an initial hash table
size of hsize entries, but this must be done after calling __pmHashInit and before any entries are added.
Entries are added to a hash table by calling __pmHashAdd. The opaque data is typically a pointer to a
block of additional information to be associated with the key, although it may be NULL if there is no ad‐
ditional information required or currently available.
Although usually not required, duplicate key values can be stored in a hash table and __pmHashAdd will
silently add these (presumably with a different data pointer). If uniqueness of keys is required, it is
necessary to call __pmHashSearch first to determine that there is no entry for key, before calling
__pmHashAdd.
Entries may be removed from a hash table using __pmHashDel where the entry to be deleted is the first one
with a matching key and data pointer. See the note above about duplicate keys to understand why the data
parameter is needed.
__pmHashSearch finds the first entry with a matching key. If duplicate keys are being stored, then the
caller will have to follow the hp->next chain looking for additional entries with the same key. Refer to
the HASHCONTROL and HASHNODE sections below for more information on the hash table internal data struc‐
tures.
__pmHashWalk provides a stateful interface to walk each node in the hash table. It is first called with
state set to PM_HASH_WALK_START to retrieve the first entry and then repeatedly called with state set to
PM_HASH_WALK_NEXT to retrieve subsequent entries.
__pmHashWalkCB provides an alternative method to traverse the hash table. The callback function cb is
called with two arguments, a pointer to the current hash entry and cdata (the latter allows the caller to
pass auxiliary information into the callback function, but can be NULL if this is not required). The
callback function must return one of the following __pmHashWalkState values:
PM_HASH_WALK_NEXT
continue the traversal
PM_HASH_WALK_STOP
terminate the traversal
PM_HASH_DELETE_NEXT
delete the current node from the hash table and continue the traversal
PM_HASH_DELETE_STOP
delete the current node from the hash table and terminate the traversal
__pmHashFree will release all storage associated with the hash table and return the hash table to the
empty state, just like after __pmHashInit has been called. But __pmHashFree cannot free any storage at‐
tached via the data argument to __pmHashAdd calls. So the most appropriate way to clean up the hash ta‐
ble is to first traverse the table releasing any data and then call __pmHashFree as the example below
shows.
__pmHashCtl hash;
__pmHashWalkState
mycallback(const __pmHashNode *hp, void *cp)
{
(void)cp;
if (hp->data) {
/*
* free() if malloc'd or some datum-specific
* method, e.g. __pmFreeProfile()
*/
free(hp->data);
}
return PM_HASH_WALK_NEXT;
}
...
__pmHashWalkCB(mycallback, NULL, &hash);
__pmHashFree(&hash);
}
__pmHashClear returns the hash table to the empty state, just like after __pmHashInit has been called.
Beware that __pmHashClear does not release any storage associated with hash entries, and so risks leaking
memory, however the following example shows how to release all memory in a single traversal of the hash
table with __pmHashWalkCB before calling __pmHashClear.
__pmHashCtl hash;
__pmHashWalkState
mycallback(const __pmHashNode *hp, void *cp)
{
(void)cp;
if (hp->data) {
/*
* free() if malloc'd or some datum-specific
* method, e.g. __pmFreeProfile()
*/
free(hp->data);
}
/*
* compared to the previous example, this difference
* is important and frees each hash node
*/
return PM_HASH_DELETE_NEXT;
}
...
__pmHashWalkCB(mycallback, NULL, &hash);
__pmHashClear(&hash);
}