From d38d2bc3533dcfb661a3cbb8bd6cd9574c31ab69 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 29 Aug 2008 15:04:49 +0200 Subject: tag: optimize tag_dup(), copy item references Don't call tag_pool_get_item() for duplicating tags, just increase the item's reference counter instead. --- src/tag.c | 4 +++- src/tag_pool.c | 43 +++++++++++++++++++++++++++++++++++++------ src/tag_pool.h | 2 ++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/tag.c b/src/tag.c index 1dffeef41..d76ba5d95 100644 --- a/src/tag.c +++ b/src/tag.c @@ -313,9 +313,11 @@ struct tag *tag_dup(const struct tag *tag) ret = tag_new(); ret->time = tag->time; + ret->numOfItems = tag->numOfItems; + ret->items = xmalloc(ret->numOfItems * sizeof(ret->items[0])); for (i = 0; i < tag->numOfItems; i++) { - tag_add_item(ret, tag->items[i]->type, tag->items[i]->value); + ret->items[i] = tag_pool_dup_item(tag->items[i]); } return ret; diff --git a/src/tag_pool.c b/src/tag_pool.c index 744a82fdb..89efef1fc 100644 --- a/src/tag_pool.c +++ b/src/tag_pool.c @@ -61,6 +61,19 @@ tag_item_to_slot(struct tag_item *item) return (struct slot*)(((char*)item) - offsetof(struct slot, item)); } +static struct slot *slot_alloc(struct slot *next, + enum tag_type type, + const char *value, int length) +{ + struct slot *slot = xmalloc(sizeof(*slot) + length); + slot->next = next; + slot->ref = 1; + slot->item.type = type; + memcpy(slot->item.value, value, length); + slot->item.value[length] = 0; + return slot; +} + struct tag_item *tag_pool_get_item(enum tag_type type, const char *value, int length) { @@ -76,16 +89,34 @@ struct tag_item *tag_pool_get_item(enum tag_type type, } } - slot = xmalloc(sizeof(*slot) + length); - slot->next = *slot_p; - slot->ref = 1; - slot->item.type = type; - memcpy(slot->item.value, value, length); - slot->item.value[length] = 0; + slot = slot_alloc(*slot_p, type, value, length); *slot_p = slot; return &slot->item; } +struct tag_item *tag_pool_dup_item(struct tag_item *item) +{ + struct slot *slot = tag_item_to_slot(item); + + assert(slot->ref > 0); + + if (slot->ref < 0xff) { + ++slot->ref; + return item; + } else { + /* the reference counter overflows above 0xff; + duplicate the item, and start with 1 */ + size_t length = strlen(item->value); + struct slot **slot_p = + &slots[calc_hash_n(item->type, item->value, + length) % NUM_SLOTS]; + slot = slot_alloc(*slot_p, item->type, + item->value, strlen(item->value)); + *slot_p = slot; + return &slot->item; + } +} + void tag_pool_put_item(struct tag_item *item) { struct slot **slot_p, *slot; diff --git a/src/tag_pool.h b/src/tag_pool.h index 4f063d1ed..e19b2f4b4 100644 --- a/src/tag_pool.h +++ b/src/tag_pool.h @@ -26,6 +26,8 @@ struct tag_item; struct tag_item *tag_pool_get_item(enum tag_type type, const char *value, int length); +struct tag_item *tag_pool_dup_item(struct tag_item *item); + void tag_pool_put_item(struct tag_item *item); #endif -- cgit v1.2.3