![]() |
Icinga-core 1.4.0
next gen monitoring
|
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