diff --git a/src/include/deque.h b/src/include/deque.h index c72064d8..83fc15df 100644 --- a/src/include/deque.h +++ b/src/include/deque.h @@ -128,6 +128,19 @@ pgagroal_deque_add_with_config(struct deque* deque, char* tag, uintptr_t data, s uintptr_t pgagroal_deque_poll(struct deque* deque, char** tag); +/** + * Retrieve value and remove the node from deque's tail. + * Note that if the value was copied into node, + * this function will return the original value and tag + * rather than making a copy of it. + * This function is thread safe, but the returned value is not protected + * @param deque The deque + * @param tag [out] Optional, tag will be returned through if not NULL + * @return The value data if deque's not empty, otherwise 0 + */ +uintptr_t +pgagroal_deque_poll_last(struct deque* deque, char** tag); + /** * Retrieve value without removing the node from deque's head. * Note that if the value was copied into node, @@ -141,6 +154,19 @@ pgagroal_deque_poll(struct deque* deque, char** tag); uintptr_t pgagroal_deque_peek(struct deque* deque, char** tag); +/** + * Retrieve value without removing the node from deque's tail. + * Note that if the value was copied into node, + * this function will return the original value and tag + * rather than making a copy of it. + * This function is thread safe, but the returned value is not protected + * @param deque The deque + * @param tag [out] Optional, tag will be returned through if not NULL + * @return The value data if deque's not empty, otherwise 0 + */ +uintptr_t +pgagroal_deque_peek_last(struct deque* deque, char** tag); + /** * Get the data for the specified tag * @param deque The deque diff --git a/src/libpgagroal/deque.c b/src/libpgagroal/deque.c index 37d0ffc9..ebd44793 100644 --- a/src/libpgagroal/deque.c +++ b/src/libpgagroal/deque.c @@ -176,6 +176,42 @@ pgagroal_deque_poll(struct deque* deque, char** tag) return data; } +uintptr_t +pgagroal_deque_poll_last(struct deque* deque, char** tag) +{ + struct deque_node* tail = NULL; + struct value* val = NULL; + uintptr_t data = 0; + if (deque == NULL || pgagroal_deque_size(deque) == 0) + { + return 0; + } + deque_write_lock(deque); + tail = deque->end->prev; + if (tail == deque->start) + { + deque_unlock(deque); + return 0; + } + // remove node + deque->end->prev = tail->prev; + tail->prev->next = deque->end; + deque->size--; + + val = tail->data; + if (tag != NULL) + { + *tag = tail->tag; + } + free(tail); + + data = pgagroal_value_data(val); + free(val); + + deque_unlock(deque); + return data; +} + uintptr_t pgagroal_deque_peek(struct deque* deque, char** tag) { @@ -202,6 +238,32 @@ pgagroal_deque_peek(struct deque* deque, char** tag) return pgagroal_value_data(val); } +uintptr_t +pgagroal_deque_peek_last(struct deque* deque, char** tag) +{ + struct deque_node* tail = NULL; + struct value* val = NULL; + if (deque == NULL || pgagroal_deque_size(deque) == 0) + { + return 0; + } + deque_read_lock(deque); + tail = deque->end->prev; + // this should not happen when size is not 0, but just in case + if (tail == deque->start) + { + deque_unlock(deque); + return 0; + } + val = tail->data; + if (tag != NULL) + { + *tag = tail->tag; + } + deque_unlock(deque); + return pgagroal_value_data(val); +} + uintptr_t pgagroal_deque_get(struct deque* deque, char* tag) {