| 447 | } |
| 448 | |
| 449 | Attribute_ID GraphContext_FindOrAddAttribute |
| 450 | ( |
| 451 | GraphContext *gc, |
| 452 | const char *attribute, |
| 453 | bool *created |
| 454 | ) { |
| 455 | ASSERT(gc); |
| 456 | |
| 457 | bool created_flag = false; |
| 458 | unsigned char *attr = (unsigned char*)attribute; |
| 459 | uint l = strlen(attribute); |
| 460 | |
| 461 | // acquire a read lock for looking up the attribute |
| 462 | pthread_rwlock_rdlock(&gc->_attribute_rwlock); |
| 463 | |
| 464 | // see if attribute already exists |
| 465 | void *attribute_id = raxFind(gc->attributes, attr, l); |
| 466 | |
| 467 | if(attribute_id == raxNotFound) { |
| 468 | // we are writing to the shared GraphContext |
| 469 | // release the held lock and re-acquire as a writer |
| 470 | pthread_rwlock_unlock(&gc->_attribute_rwlock); |
| 471 | pthread_rwlock_wrlock(&gc->_attribute_rwlock); |
| 472 | |
| 473 | // lookup the attribute again now that we are in a critical region |
| 474 | attribute_id = raxFind(gc->attributes, attr, l); |
| 475 | |
| 476 | // if set by another thread, use the retrieved value |
| 477 | if(attribute_id == raxNotFound) { |
| 478 | // otherwise, it will be assigned an ID |
| 479 | // equal to the current mapping size |
| 480 | attribute_id = (void *)raxSize(gc->attributes); |
| 481 | // insert the new attribute key and ID |
| 482 | raxInsert(gc->attributes, attr, l, attribute_id, NULL); |
| 483 | array_append(gc->string_mapping, rm_strdup(attribute)); |
| 484 | created_flag = true; |
| 485 | |
| 486 | // new attribute been added, update graph version |
| 487 | _GraphContext_UpdateVersion(gc, attribute); |
| 488 | } |
| 489 | } |
| 490 | |
| 491 | // release the lock |
| 492 | pthread_rwlock_unlock(&gc->_attribute_rwlock); |
| 493 | |
| 494 | if(created) { |
| 495 | *created = created_flag; |
| 496 | } |
| 497 | |
| 498 | return (uintptr_t)attribute_id; |
| 499 | } |
| 500 | |
| 501 | const char *GraphContext_GetAttributeString |
| 502 | ( |
no test coverage detected