Icinga-core 1.4.0
next gen monitoring
common/skiplist.c
Go to the documentation of this file.
00001 /************************************************************************
00002  *
00003  * SKIPLIST.C - Skiplist functions for use in Icinga event/object lists
00004  *
00005  * Copyright (c) 2008 Ethan Galstad
00006  * Copyright (c) 2009-2011 Nagios Core Development Team and Community Contributors
00007  * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org)
00008  *
00009  * Notes:
00010  * 
00011  * These function implement a slightly modified skiplist from that
00012  * described by William Pugh (ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf).
00013  * The structures and function were modified to allow the list to act
00014  * like a priority queue for the Icinga event list/queue(s).  Multiple nodes with
00015  * the same key value are allowed on the list to accomodate multiple events
00016  * occurring at the same (second) point in time.  Implemented peek() and pop()
00017  * functions to allow for quick event queue processing, and a method to delete
00018  * a specific list item, based on its pointer, rather than its data value.  Again,
00019  * this is useful for the Icinga event queue.
00020  *
00021  * License:
00022  *
00023  * This program is free software; you can redistribute it and/or modify
00024  * it under the terms of the GNU General Public License version 2 as
00025  * published by the Free Software Foundation.
00026  *
00027  * This program is distributed in the hope that it will be useful,
00028  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00029  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00030  * GNU General Public License for more details.
00031  *
00032  * You should have received a copy of the GNU General Public License
00033  * along with this program; if not, write to the Free Software
00034  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00035  ************************************************************************/
00036 
00037 #include "../include/config.h"
00038 #include "../include/common.h"
00039 
00040 #include "../include/skiplist.h"
00041 
00042 
00043 
00044 skiplist *skiplist_new(int max_levels, float level_probability, int allow_duplicates, int append_duplicates, int (*compare_function)(void *,void *)){
00045         skiplist *newlist=NULL;
00046 
00047         /* alloc memory for new list structure */
00048         if((newlist=(skiplist *)malloc(sizeof(skiplist)))){
00049 
00050                 /* initialize levels, etc. */
00051                 newlist->current_level=0;
00052                 newlist->max_levels=max_levels;
00053                 newlist->level_probability=level_probability;
00054                 newlist->allow_duplicates=allow_duplicates;
00055                 newlist->append_duplicates=append_duplicates;
00056                 newlist->items=0;
00057                 newlist->compare_function=compare_function;
00058 
00059                 /* initialize head node */
00060                 newlist->head=skiplist_new_node(newlist,max_levels);
00061                 }
00062 
00063         return newlist;
00064         }
00065 
00066 
00067 int skiplist_insert(skiplist *list, void *data){
00068         skiplistnode **update=NULL;
00069         skiplistnode *thisnode=NULL;
00070         skiplistnode *nextnode=NULL;
00071         skiplistnode *newnode=NULL;
00072         int level=0;
00073 
00074         if(list==NULL || data==NULL){
00075                 return SKIPLIST_ERROR_ARGS;
00076                 }
00077 
00078         /* check to make sure we don't have duplicates */
00079         /* NOTE: this could made be more efficient */
00080         if(list->allow_duplicates==FALSE){
00081                 if(skiplist_find_first(list,data,NULL))
00082                         return SKIPLIST_ERROR_DUPLICATE;
00083                 }
00084 
00085         /* initialize update vector */
00086         if((update=(skiplistnode **)calloc(list->max_levels, sizeof(skiplistnode *)))==NULL)
00087                 return SKIPLIST_ERROR_MEMORY;
00088 
00089         /* find proper position for insert, remember pointers  with an update vector */
00090         thisnode=list->head;
00091         for(level=list->current_level;level>=0;level--){
00092 
00093                 while((nextnode=thisnode->forward[level])){
00094                         if(list->append_duplicates==TRUE){
00095                                 if(list->compare_function(nextnode->data,data)>0)
00096                                         break;
00097                                 }
00098                         else{
00099                                 if(list->compare_function(nextnode->data,data)>=0)
00100                                         break;
00101                                 }
00102                         thisnode=nextnode;
00103                         }
00104 
00105                 update[level]=thisnode;
00106                 }
00107 
00108         /* get a random level the new node should be inserted at */
00109         level=skiplist_random_level(list);
00110         /*printf("INSERTION LEVEL: %d\n",level);*/
00111 
00112         /* we're adding a new level... */
00113         if(level > list->current_level){
00114                 /*printf("NEW LEVEL!\n");*/
00115                 list->current_level++;
00116                 level=list->current_level;
00117                 update[level]=list->head;
00118                 }
00119 
00120         /* create a new node */
00121         if((newnode=skiplist_new_node(list,level))==NULL){
00122                 /*printf("NODE ERROR\n");*/
00123                 free(update);
00124                 return SKIPLIST_ERROR_MEMORY;
00125                 }
00126         newnode->data=data;
00127 
00128         /* update pointers to insert node at proper location */
00129         do{
00130                 thisnode=update[level];
00131                 newnode->forward[level]=thisnode->forward[level];
00132                 thisnode->forward[level]=newnode;
00133 
00134                 }while(--level>=0);
00135 
00136         /* update counters */
00137         list->items++;
00138 
00139         /* free memory */
00140         free(update);
00141 
00142         return SKIPLIST_OK;
00143         }
00144 
00145 
00146 
00147 skiplistnode *skiplist_new_node(skiplist *list, int node_levels){
00148         skiplistnode *newnode=NULL;
00149         register int x=0;
00150 
00151         if(list==NULL)
00152                 return NULL;
00153 
00154         if(node_levels<0 || node_levels>list->max_levels)
00155                 return NULL;
00156 
00157         /* allocate memory for node + variable number of level pointers */
00158         if((newnode=(skiplistnode *)malloc(sizeof(skiplistnode) + (node_levels * sizeof(skiplistnode *))))){
00159 
00160                 /* initialize forward pointers */
00161                 for(x=0;x<node_levels;x++)
00162                         newnode->forward[x]=NULL;
00163 
00164                 /* initialize data pointer */
00165                 newnode->data=NULL;
00166                 }
00167 
00168         return newnode;
00169         }
00170 
00171 
00172 int skiplist_random_level(skiplist *list){
00173         int level=0;
00174         float r=0.0;
00175 
00176         if(list==NULL)
00177                 return -1;
00178 
00179         for(level=0;level<list->max_levels;level++){
00180                 r=((float)rand()/(float)RAND_MAX);
00181                 if(r>list->level_probability)
00182                         break;
00183                 }
00184 
00185         return (level >= list->max_levels)?list->max_levels-1:level;
00186         }
00187 
00188 
00189 int skiplist_empty(skiplist *list){
00190         skiplistnode *this=NULL;
00191         skiplistnode *next=NULL;
00192         int level=0;
00193 
00194         if(list==NULL)
00195                 return ERROR;
00196 
00197         /* free all list nodes (but not header) */
00198         for(this=list->head->forward[0];this!=NULL;this=next){
00199                 next=this->forward[0];
00200                 free(this);
00201                 }
00202 
00203         /* reset level pointers */
00204         for(level=list->current_level;level>=0;level--)
00205                 list->head->forward[level]=NULL;
00206 
00207         /* reset list level */
00208         list->current_level=0;
00209 
00210         /* reset items */
00211         list->items=0;
00212 
00213         return OK;
00214         }
00215 
00216 
00217 
00218 int skiplist_free(skiplist **list){
00219         skiplistnode *this=NULL;
00220         skiplistnode *next=NULL;
00221 
00222         if(list==NULL)
00223                 return ERROR;
00224         if(*list==NULL)
00225                 return OK;
00226 
00227         /* free header and all list nodes */
00228         for(this=(*list)->head;this!=NULL;this=next){
00229                 next=this->forward[0];
00230                 free(this);
00231                 }
00232 
00233         /* free list structure */
00234         free(*list);
00235         *list=NULL;
00236 
00237         return OK;
00238         }
00239 
00240 
00241 
00242 /* get first item in list */
00243 void *skiplist_peek(skiplist *list){
00244 
00245         if(list==NULL)
00246                 return NULL;
00247 
00248         /* return first item */
00249         return list->head->forward[0]->data;
00250         }
00251 
00252 
00253 
00254 /* get/remove first item in list */
00255 void *skiplist_pop(skiplist *list){
00256         skiplistnode *thisnode=NULL;
00257         void *data=NULL;
00258         int level=0;
00259 
00260         if(list==NULL)
00261                 return NULL;
00262 
00263         /* get first item */
00264         thisnode=list->head->forward[0];
00265         if(thisnode==NULL)
00266                 return NULL;
00267 
00268         /* get data for first item */
00269         data=thisnode->data;
00270 
00271         /* remove first item from queue - update forward links from head to first node */
00272         for(level=0;level<=list->current_level;level++){
00273                 if(list->head->forward[level]==thisnode)
00274                         list->head->forward[level]=thisnode->forward[level];
00275                 }
00276 
00277         /* free deleted node */
00278         free(thisnode);
00279 
00280         /* adjust items */
00281         list->items--;
00282 
00283         return data;
00284         }
00285 
00286 
00287 
00288 /* get first item in list */
00289 void *skiplist_get_first(skiplist *list, void **node_ptr){
00290         skiplistnode *thisnode=NULL;
00291 
00292         if(list==NULL)
00293                 return NULL;
00294 
00295         /* get first node */
00296         thisnode=list->head->forward[0];
00297 
00298         /* return pointer to node */
00299         if(node_ptr)
00300                 *node_ptr=(void *)thisnode;
00301 
00302         if(thisnode)
00303                 return thisnode->data;
00304         else
00305                 return NULL;
00306         }
00307 
00308 
00309 
00310 /* get next item in list */
00311 void *skiplist_get_next(void **node_ptr){
00312         skiplistnode *thisnode=NULL;
00313         skiplistnode *nextnode=NULL;
00314 
00315         if(node_ptr==NULL || *node_ptr==NULL)
00316                 return NULL;
00317 
00318         thisnode=(skiplistnode *)(*node_ptr);
00319         nextnode=thisnode->forward[0];
00320 
00321         *node_ptr=(void *)nextnode;
00322 
00323         if(nextnode)
00324                 return nextnode->data;
00325         else
00326                 return NULL;
00327         }
00328 
00329 
00330 
00331 /* first first item in list */
00332 void *skiplist_find_first(skiplist *list, void *data, void **node_ptr){
00333         skiplistnode *thisnode=NULL;
00334         skiplistnode *nextnode=NULL;
00335         int level=0;
00336 
00337         if(list==NULL || data==NULL)
00338                 return NULL;
00339 
00340         thisnode=list->head;
00341         for(level=list->current_level;level>=0;level--){
00342                 while((nextnode=thisnode->forward[level])){
00343                         if(list->compare_function(nextnode->data,data)>=0)
00344                                 break;
00345                         thisnode=nextnode;
00346                         }
00347                 }
00348 
00349         /* we found it! */
00350         if(nextnode && list->compare_function(nextnode->data,data)==0){
00351                 if(node_ptr)
00352                         *node_ptr=(void *)nextnode;
00353                 return nextnode->data;
00354                 }
00355         else{
00356                 if(node_ptr)
00357                         *node_ptr=NULL;
00358                 }
00359 
00360         return NULL;
00361         }
00362 
00363 
00364 
00365 /* find next match */
00366 void *skiplist_find_next(skiplist *list, void *data, void **node_ptr){
00367         skiplistnode *thisnode=NULL;
00368         skiplistnode *nextnode=NULL;
00369 
00370         if(list==NULL || data==NULL || node_ptr==NULL)
00371                 return NULL;
00372         if(*node_ptr==NULL)
00373                 return NULL;
00374 
00375         thisnode=(skiplistnode *)(*node_ptr);
00376         nextnode=thisnode->forward[0];
00377 
00378         if(nextnode){
00379                 if(list->compare_function(nextnode->data,data)==0){
00380                         *node_ptr=(void *)nextnode;
00381                         return nextnode->data;
00382                         }
00383                 }
00384 
00385         *node_ptr=NULL;
00386         return NULL;
00387         }
00388 
00389 
00390 
00391 /* delete (all) matching item(s) from list */
00392 int skiplist_delete(skiplist *list, void *data){
00393 
00394         return skiplist_delete_all(list,data);
00395         }
00396 
00397 
00398 
00399 /* delete first matching item from list */
00400 int skiplist_delete_first(skiplist *list, void *data){
00401         skiplistnode **update=NULL;
00402         skiplistnode *thisnode=NULL;
00403         skiplistnode *nextnode=NULL;
00404         int level=0;
00405         int top_level=0;
00406         int deleted=FALSE;
00407         int x=0;
00408 
00409         if(list==NULL || data==NULL)
00410                 return ERROR;
00411 
00412         /* initialize update vector */
00413         if((update=(skiplistnode **)malloc(sizeof(skiplistnode *) * list->max_levels))==NULL)
00414                 return ERROR;
00415         for(x=0;x<list->max_levels;x++)
00416                 update[x]=NULL;
00417 
00418         /* find location in list */
00419         thisnode=list->head;
00420         for(top_level=level=list->current_level;level>=0;level--){
00421                 while((nextnode=thisnode->forward[level])){
00422                         if(list->compare_function(nextnode->data,data)>=0)
00423                                 break;
00424                         thisnode=nextnode;
00425                         }
00426                 update[level]=thisnode;
00427                 }
00428 
00429         /* we found a match! */
00430         if(list->compare_function(nextnode->data,data)==0){
00431 
00432                 /* adjust level pointers to bypass (soon to be) removed node */
00433                 for(level=0;level<=top_level;level++){
00434 
00435                         thisnode=update[level];
00436                         if(thisnode->forward[level]!=nextnode)
00437                                 break;
00438 
00439                         thisnode->forward[level]=nextnode->forward[level];
00440                         }
00441 
00442                 /* free node memory */
00443                 free(nextnode);
00444 
00445                 /* adjust top/current level of list is necessary */
00446                 while(list->head->forward[top_level]==NULL && top_level>0)
00447                         top_level--;
00448                 list->current_level=top_level;
00449 
00450                 /* adjust items */
00451                 list->items--;
00452 
00453                 deleted=TRUE;
00454                 }
00455 
00456         /* free memory */
00457         free(update);
00458 
00459         return deleted;
00460         }
00461 
00462 
00463 
00464 /* delete all matching items from list */
00465 int skiplist_delete_all(skiplist *list, void *data){
00466         int deleted=0;
00467         int total_deleted=0;
00468 
00469         /* NOTE: there is a more efficient way to do this... */
00470         while((deleted=skiplist_delete_first(list,data))==1)
00471                 total_deleted++;
00472 
00473         return total_deleted;
00474         }
00475 
00476 
00477 
00478 /* delete specific node from list */
00479 int skiplist_delete_node(skiplist *list, void *node_ptr){
00480         void *data=NULL;
00481         skiplistnode **update=NULL;
00482         skiplistnode *thenode=NULL;
00483         skiplistnode *thisnode=NULL;
00484         skiplistnode *nextnode=NULL;
00485         int level=0;
00486         int top_level=0;
00487         int deleted=FALSE;
00488         int x=0;
00489 
00490         if(list==NULL || node_ptr==NULL)
00491                 return ERROR;
00492 
00493         /* we'll need the data from the node to first find the node */
00494         thenode=(skiplistnode *)node_ptr;
00495         data=thenode->data;
00496 
00497         /* initialize update vector */
00498         if((update=(skiplistnode **)malloc(sizeof(skiplistnode *) * list->max_levels))==NULL)
00499                 return ERROR;
00500         for(x=0;x<list->max_levels;x++)
00501                 update[x]=NULL;
00502 
00503         /* find location in list */
00504         thisnode=list->head;
00505         for(top_level=level=list->current_level;level>=0;level--){
00506                 while((nextnode=thisnode->forward[level])){
00507 
00508                         /* next node would be too far */
00509                         if(list->compare_function(nextnode->data,data)>0)
00510                                 break;
00511                         /* this is the exact node we want */
00512                         if(list->compare_function(nextnode->data,data)==0 && nextnode==thenode)
00513                                 break;
00514 
00515                         thisnode=nextnode;
00516                         }
00517                 update[level]=thisnode;
00518                 }
00519 
00520         /* we found a match! (value + pointers match) */
00521         if(nextnode && list->compare_function(nextnode->data,data)==0 && nextnode==thenode){
00522 
00523                 /* adjust level pointers to bypass (soon to be) removed node */
00524                 for(level=0;level<=top_level;level++){
00525 
00526                         thisnode=update[level];
00527                         if(thisnode->forward[level]!=nextnode)
00528                                 break;
00529 
00530                         thisnode->forward[level]=nextnode->forward[level];
00531                         }
00532 
00533                 /* free node memory */
00534                 free(nextnode);
00535 
00536                 /* adjust top/current level of list is necessary */
00537                 while(list->head->forward[top_level]==NULL && top_level>0)
00538                         top_level--;
00539                 list->current_level=top_level;
00540 
00541                 /* adjust items */
00542                 list->items--;
00543 
00544                 deleted=TRUE;
00545                 }
00546 
00547         /* free memory */
00548         free(update);
00549 
00550         return deleted;
00551         }
00552 
00553 
00554 
 All Data Structures Files Functions Variables Typedefs Defines