diff --git a/src/include/art.h b/src/include/art.h index cd70d52a..bf4aef1c 100644 --- a/src/include/art.h +++ b/src/include/art.h @@ -74,7 +74,7 @@ int pgagroal_art_create(struct art** tree); /** - * inserts a new value into the art tree, note that the key is copied + * inserts a new value into the art tree,note that the key is copied while the value is sometimes not(depending on value type) * @param t The tree * @param key The key * @param key_len The length of the key @@ -85,6 +85,18 @@ pgagroal_art_create(struct art** tree); int pgagroal_art_insert(struct art* t, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type); +/** + * inserts a new ValueRef value into the art tree with a custom to_string and destroy data callback config + * @param t The tree + * @param key The key + * @param key_len The length of the key + * @param value The value data + * @param config The config + * @return 0 if the item was successfully inserted, otherwise 1 + */ +int +pgagroal_art_insert_with_config(struct art* t, unsigned char* key, uint32_t key_len, uintptr_t value, struct value_config* config); + /** * Check if a key exists in the ART tree * @param t The tree diff --git a/src/include/deque.h b/src/include/deque.h index 472888b3..214edc4b 100644 --- a/src/include/deque.h +++ b/src/include/deque.h @@ -25,6 +25,7 @@ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef PGAGROAL_DEQUE_H #define PGAGROAL_DEQUE_H @@ -82,7 +83,7 @@ int pgagroal_deque_create(bool thread_safe, struct deque** deque); /** - * Add a node to deque's tail, the tag will be copied, but the data will not + * Add a node to deque's tail, the tag will be copied * This function is thread safe * @param deque The deque * @param tag The tag,optional @@ -93,6 +94,27 @@ pgagroal_deque_create(bool thread_safe, struct deque** deque); int pgagroal_deque_add(struct deque* deque, char* tag, uintptr_t data, enum value_type type); +/** + * Remove all the nodes with the given tag + * @param deque The deque + * @param tag The tag + * @return Number of nodes removed + */ +int +pgagroal_deque_remove(struct deque* deque, char* tag); + +/** + * Add a node to deque's tail with custom to_string and data destroy callback, + * the type will be set to ValueRef + * This function is thread safe + * @param deque The deque + * @param tag The tag,optional + * @param data The data + * @return 0 if success, otherwise 1 + */ +int +pgagroal_deque_add_with_config(struct deque* deque, char* tag, uintptr_t data, struct value_config* config); + /** * Retrieve value and remove the node from deque's head. * Note that if the value was copied into node, @@ -128,6 +150,15 @@ pgagroal_deque_peek(struct deque* deque, char** tag); uintptr_t pgagroal_deque_get(struct deque* deque, char* tag); +/** + * Does the tag exists + * @param deque The deque + * @param tag The tag + * @return True if exists, otherwise false + */ +bool +pgagroal_deque_exists(struct deque* deque, char* tag); + /** * Create a deque iterator * @param deque The deque @@ -182,6 +213,13 @@ pgagroal_deque_empty(struct deque* deque); void pgagroal_deque_list(struct deque* deque); +/** + * Sort the deque + * @param deque The deque + */ +void +pgagroal_deque_sort(struct deque* deque); + /** * Convert what's inside deque to string * @param deque The deque diff --git a/src/include/value.h b/src/include/value.h index 40c460cd..c2ac0680 100644 --- a/src/include/value.h +++ b/src/include/value.h @@ -73,9 +73,21 @@ struct value data_to_string_cb to_string; /**< The callback to convert data to string */ }; +/** + * @struct value_config + * Defines configuration for managing a value + */ +struct value_config +{ + data_destroy_cb destroy_data; /**< The callback to destroy data */ + data_to_string_cb to_string; /**< The callback to convert data to string */ +}; + /** * Create a value based on the data and value type - * @param type The value type, use ValueRef if you are only storing pointers without the need to manage memory + * @param type The value type, use ValueRef if you are only storing pointers without the need to manage memory, + * use ValueMem if you are storing pointers to a chunk of memory that needs to and can be simply freed + * (meaning it can't have pointers to other malloced memories) * @param data The value data, type cast it to uintptr_t before passing into function * @param value [out] The value * @return 0 on success, 1 if otherwise @@ -83,6 +95,17 @@ struct value int pgagroal_value_create(enum value_type type, uintptr_t data, struct value** value); +/** + * Create a value with a config for customized destroy or to_string callback, + * the type will default to ValueRef + * @param data The value data, type cast it to uintptr_t before passing into function + * @param config The configuration + * @param value [out] The value + * @return 0 on success, 1 if otherwise + */ +int +pgagroal_value_create_with_config(uintptr_t data, struct value_config* config, struct value** value); + /** * Destroy a value along with the data within * @param value The value @@ -146,4 +169,4 @@ pgagroal_value_to_float(uintptr_t val); } #endif -#endif \ No newline at end of file +#endif diff --git a/src/libpgagroal/art.c b/src/libpgagroal/art.c index 063ca372..1d13a9c5 100644 --- a/src/libpgagroal/art.c +++ b/src/libpgagroal/art.c @@ -134,7 +134,7 @@ static struct art_leaf* node_get_minimum(struct art_node* node); static void -create_art_leaf(struct art_leaf** leaf, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type); +create_art_leaf(struct art_leaf** leaf, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type, struct value_config* config); static void create_art_node(struct art_node** node, enum art_node_type type); @@ -214,11 +214,12 @@ find_index(unsigned char ch, const unsigned char* keys, int length); * @param key_len The length of the key * @param value The value data * @param type The value type + * @param config The config * @param new If the key value is newly inserted (not replaced) * @return Old value if the key exists, otherwise NULL */ static struct value* -art_node_insert(struct art_node* node, struct art_node** node_ref, uint32_t depth, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type, bool* new); +art_node_insert(struct art_node* node, struct art_node** node_ref, uint32_t depth, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type, struct value_config* config, bool* new); /** * Delete a value from a node recursively. @@ -352,7 +353,28 @@ pgagroal_art_insert(struct art* t, unsigned char* key, uint32_t key_len, uintptr // c'mon, at least create a tree first... goto error; } - old_val = art_node_insert(t->root, &t->root, 0, key, key_len, value, type, &new); + old_val = art_node_insert(t->root, &t->root, 0, key, key_len, value, type, NULL, &new); + pgagroal_value_destroy(old_val); + if (new) + { + t->size++; + } + return 0; +error: + return 1; +} + +int +pgagroal_art_insert_with_config(struct art* t, unsigned char* key, uint32_t key_len, uintptr_t value, struct value_config* config) +{ + struct value* old_val = NULL; + bool new = false; + if (t == NULL) + { + // c'mon, at least create a tree first... + goto error; + } + old_val = art_node_insert(t->root, &t->root, 0, key, key_len, value, ValueRef, config, &new); pgagroal_value_destroy(old_val); if (new) { @@ -407,12 +429,20 @@ min(uint32_t a, uint32_t b) } static void -create_art_leaf(struct art_leaf** leaf, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type) +create_art_leaf(struct art_leaf** leaf, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type, struct value_config* config) { struct art_leaf* l = NULL; l = malloc(sizeof(struct art_leaf) + key_len); memset(l, 0, sizeof(struct art_leaf) + key_len); - pgagroal_value_create(type, value, &l->value); + if (config != NULL) + { + pgagroal_value_create_with_config(value, config, &l->value); + } + else + { + pgagroal_value_create(type, value, &l->value); + } + l->key_len = key_len; memcpy(l->key, key, key_len); *leaf = l; @@ -602,7 +632,7 @@ node_get_child(struct art_node* node, unsigned char ch) } static struct value* -art_node_insert(struct art_node* node, struct art_node** node_ref, uint32_t depth, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type, bool* new) +art_node_insert(struct art_node* node, struct art_node** node_ref, uint32_t depth, unsigned char* key, uint32_t key_len, uintptr_t value, enum value_type type, struct value_config* config, bool* new) { struct art_leaf* leaf = NULL; struct art_leaf* min_leaf = NULL; @@ -616,7 +646,7 @@ art_node_insert(struct art_node* node, struct art_node** node_ref, uint32_t dept { // Lazy expansion, skip creating an inner node since it currently will have only this one leaf. // We will compare keys when reach leaf anyway, the path doesn't need to 100% match the key along the way - create_art_leaf(&leaf, key, key_len, value, type); + create_art_leaf(&leaf, key, key_len, value, type, config); *node_ref = SET_LEAF(leaf); *new = true; return NULL; @@ -639,7 +669,7 @@ art_node_insert(struct art_node* node, struct art_node** node_ref, uint32_t dept // This way we inductively guarantee that all children to a parent share the same prefix even if it's only partially stored leaf_key = GET_LEAF(node)->key; create_art_node(&new_node, Node4); - create_art_leaf(&leaf, key, key_len, value, type); + create_art_leaf(&leaf, key, key_len, value, type, config); // Get the diverging index after point of depth for (idx = depth; idx < min(key_len, GET_LEAF(node)->key_len); idx++) { @@ -681,7 +711,7 @@ art_node_insert(struct art_node* node, struct art_node** node_ref, uint32_t dept { // case 2, split the node create_art_node(&new_node, Node4); - create_art_leaf(&leaf, key, key_len, value, type); + create_art_leaf(&leaf, key, key_len, value, type, config); new_node->prefix_len = diff_len; memcpy(new_node->prefix, node->prefix, min(MAX_PREFIX_LEN, diff_len)); // We need to know if new bytes that were once outside the partial prefix range will now come into the range @@ -727,12 +757,12 @@ art_node_insert(struct art_node* node, struct art_node** node_ref, uint32_t dept { node->num_children++; } - return art_node_insert(*next, next, depth + 1, key, key_len, value, type, new); + return art_node_insert(*next, next, depth + 1, key, key_len, value, type, config, new); } else { // add a child to current node since the spot is available - create_art_leaf(&leaf, key, key_len, value, type); + create_art_leaf(&leaf, key, key_len, value, type, config); node_add_child(node, node_ref, key[depth], SET_LEAF(leaf)); *new = true; return NULL; diff --git a/src/libpgagroal/deque.c b/src/libpgagroal/deque.c index ee84d1b5..f6258456 100644 --- a/src/libpgagroal/deque.c +++ b/src/libpgagroal/deque.c @@ -36,11 +36,11 @@ // tag is copied if not NULL static void -deque_offer(struct deque* deque, char* tag, uintptr_t data, enum value_type type); +deque_offer(struct deque* deque, char* tag, uintptr_t data, enum value_type type, struct value_config* config); // tag is copied if not NULL static void -deque_node_create(uintptr_t data, enum value_type type, char* tag, struct deque_node** node); +deque_node_create(uintptr_t data, enum value_type type, char* tag, struct value_config* config, struct deque_node** node); // tag will always be freed static void @@ -73,6 +73,18 @@ to_text_string(struct deque* deque, char* tag, int indent); static struct deque_node* deque_remove(struct deque* deque, struct deque_node* node); +static struct deque_node* +get_middle(struct deque_node* node); + +static struct deque_node* +deque_sort(struct deque_node* node); + +static struct deque_node* +deque_merge(struct deque_node* node1, struct deque_node* node2); + +static int +tag_compare(char* tag1, char* tag2); + int pgagroal_deque_create(bool thread_safe, struct deque** deque) { @@ -84,8 +96,8 @@ pgagroal_deque_create(bool thread_safe, struct deque** deque) { pthread_rwlock_init(&q->mutex, NULL); } - deque_node_create(0, ValueInt32, NULL, &q->start); - deque_node_create(0, ValueInt32, NULL, &q->end); + deque_node_create(0, ValueInt32, NULL, NULL, &q->start); + deque_node_create(0, ValueInt32, NULL, NULL, &q->end); q->start->next = q->end; q->end->prev = q->start; *deque = q; @@ -95,7 +107,36 @@ pgagroal_deque_create(bool thread_safe, struct deque** deque) int pgagroal_deque_add(struct deque* deque, char* tag, uintptr_t data, enum value_type type) { - deque_offer(deque, tag, data, type); + deque_offer(deque, tag, data, type, NULL); + return 0; +} + +int +pgagroal_deque_remove(struct deque* deque, char* tag) +{ + int cnt = 0; + struct deque_iterator* iter = NULL; + if (deque == NULL || tag == NULL) + { + return 0; + } + pgagroal_deque_iterator_create(deque, &iter); + while (pgagroal_deque_iterator_next(iter)) + { + if (pgagroal_compare_string(iter->tag, tag)) + { + pgagroal_deque_iterator_remove(iter); + cnt++; + } + } + pgagroal_deque_iterator_destroy(iter); + return cnt; +} + +int +pgagroal_deque_add_with_config(struct deque* deque, char* tag, uintptr_t data, struct value_config* config) +{ + deque_offer(deque, tag, data, ValueRef, config); return 0; } @@ -180,6 +221,25 @@ pgagroal_deque_get(struct deque* deque, char* tag) return 0; } +bool +pgagroal_deque_exists(struct deque* deque, char* tag) +{ + bool ret = false; + struct deque_node* n = NULL; + + deque_read_lock(deque); + + n = deque_find(deque, tag); + if (n != NULL) + { + ret = true; + } + + deque_unlock(deque); + + return ret; +} + bool pgagroal_deque_empty(struct deque* deque) { @@ -198,6 +258,35 @@ pgagroal_deque_list(struct deque* deque) } } +void +pgagroal_deque_sort(struct deque* deque) +{ + deque_write_lock(deque); + if (deque == NULL || deque->start == NULL || deque->end == NULL || deque->size <= 1) + { + deque_unlock(deque); + return; + } + // break the connection to start and end node since we are going to move nodes around + struct deque_node* first = deque->start->next; + struct deque_node* last = deque->end->prev; + struct deque_node* node = NULL; + first->prev = NULL; + last->next = NULL; + deque->start->next = NULL; + deque->end->prev = NULL; + node = deque_sort(first); + deque->start->next = node; + node->prev = deque->start; + while (node->next != NULL) + { + node = node->next; + } + deque->end->prev = node; + node->next = deque->end; + deque_unlock(deque); +} + void pgagroal_deque_destroy(struct deque* deque) { @@ -318,11 +407,11 @@ pgagroal_deque_iterator_next(struct deque_iterator* iter) } static void -deque_offer(struct deque* deque, char* tag, uintptr_t data, enum value_type type) +deque_offer(struct deque* deque, char* tag, uintptr_t data, enum value_type type, struct value_config* config) { struct deque_node* n = NULL; struct deque_node* last = NULL; - deque_node_create(data, type, tag, &n); + deque_node_create(data, type, tag, config, &n); deque_write_lock(deque); deque->size++; last = deque->end->prev; @@ -334,16 +423,22 @@ deque_offer(struct deque* deque, char* tag, uintptr_t data, enum value_type type } static void -deque_node_create(uintptr_t data, enum value_type type, char* tag, struct deque_node** node) +deque_node_create(uintptr_t data, enum value_type type, char* tag, struct value_config* config, struct deque_node** node) { struct deque_node* n = NULL; n = malloc(sizeof(struct deque_node)); memset(n, 0, sizeof(struct deque_node)); - pgagroal_value_create(type, data, &n->data); + if (config != NULL) + { + pgagroal_value_create_with_config(data, config, &n->data); + } + else + { + pgagroal_value_create(type, data, &n->data); + } if (tag != NULL) { - n->tag = malloc(strlen(tag) + 1); - strcpy(n->tag, tag); + n->tag = pgagroal_append(NULL, tag); } else { @@ -566,3 +661,125 @@ deque_remove(struct deque* deque, struct deque_node* node) deque->size--; return prev; } + +static struct deque_node* +get_middle(struct deque_node* node) +{ + struct deque_node* slow = node; + struct deque_node* fast = node; + while (fast != NULL && fast->next != NULL) + { + slow = slow->next; + fast = fast->next->next; + } + return slow; +} + +static struct deque_node* +deque_sort(struct deque_node* node) +{ + struct deque_node* mid = NULL; + struct deque_node* prevmid = NULL; + struct deque_node* node1 = NULL; + struct deque_node* node2 = NULL; + if (node == NULL || node->next == NULL) + { + return node; + } + mid = get_middle(node); + prevmid = mid->prev; + mid->prev = NULL; + prevmid->next = NULL; + node1 = deque_sort(node); + node2 = deque_sort(mid); + return deque_merge(node1, node2); +} + +static struct deque_node* +deque_merge(struct deque_node* node1, struct deque_node* node2) +{ + struct deque_node* node = NULL; + struct deque_node* left = node1; + struct deque_node* right = node2; + struct deque_node* next = NULL; + struct deque_node* start = NULL; + if (node1 == NULL) + { + return node2; + } + if (node2 == NULL) + { + return node1; + } + while (left != NULL && right != NULL) + { + if (tag_compare(left->tag, right->tag) <= 0) + { + next = left->next; + if (node == NULL) + { + start = left; + node = left; + node->prev = NULL; + node->next = NULL; + } + else + { + node->next = left; + left->prev = node; + left->next = NULL; + node = node->next; + } + left = next; + } + else + { + next = right->next; + if (node == NULL) + { + start = right; + node = right; + node->prev = NULL; + node->next = NULL; + } + else + { + node->next = right; + right->prev = node; + right->next = NULL; + node = node->next; + } + right = next; + } + } + while (left != NULL) + { + next = left->next; + node->next = left; + left->prev = node; + left = next; + node = node->next; + } + while (right != NULL) + { + next = right->next; + node->next = right; + right->prev = node; + right = next; + node = node->next; + } + return start; +} +static int +tag_compare(char* tag1, char* tag2) +{ + if (tag1 == NULL) + { + return tag2 == NULL ? 0 : 1; + } + if (tag2 == NULL) + { + return tag1 == NULL ? 0 : -1; + } + return strcmp(tag1, tag2); +} diff --git a/src/libpgagroal/value.c b/src/libpgagroal/value.c index b9e3375a..ce30e0eb 100644 --- a/src/libpgagroal/value.c +++ b/src/libpgagroal/value.c @@ -25,7 +25,6 @@ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - /* pgagroal */ #include #include @@ -128,6 +127,7 @@ pgagroal_value_create(enum value_type type, uintptr_t data, struct value** value val->to_string = art_to_string_cb; break; case ValueMem: + case ValueRef: val->to_string = mem_to_string_cb; break; default: @@ -176,6 +176,27 @@ pgagroal_value_create(enum value_type type, uintptr_t data, struct value** value return 1; } +int +pgagroal_value_create_with_config(uintptr_t data, struct value_config* config, struct value** value) +{ + if (pgagroal_value_create(ValueRef, data, value)) + { + return 1; + } + if (config != NULL) + { + if (config->destroy_data != NULL) + { + (*value)->destroy_data = config->destroy_data; + } + if (config->to_string != NULL) + { + (*value)->to_string = config->to_string; + } + } + return 0; +} + int pgagroal_value_destroy(struct value* value) { @@ -289,11 +310,11 @@ json_destroy_cb(uintptr_t data) static char* noop_to_string_cb(uintptr_t data, int32_t format, char* tag, int indent) { + char* ret = NULL; + ret = pgagroal_indent(ret, tag, indent); (void) data; - (void) tag; - (void) indent; (void) format; - return NULL; + return ret; } static char*