diff --git a/include/maxscale/buffer.h b/include/maxscale/buffer.h index 12c1500ca..863268968 100644 --- a/include/maxscale/buffer.h +++ b/include/maxscale/buffer.h @@ -24,22 +24,6 @@ * included that point to the first valid byte in the buffer and the first byte after the * last valid byte. This allows data to be consumed from either end of the buffer whilst * still allowing for the copy free semantics of the buffering system. - * - * @verbatim - * Revision History - * - * Date Who Description - * 10/06/2013 Mark Riddoch Initial implementation - * 11/07/2013 Mark Riddoch Addition of reference count in the gwbuf - * 16/07/2013 Massimiliano Pinto Added command type for the queue - * 10/07/2014 Mark Riddoch Addition of hints - * 15/07/2014 Mark Riddoch Added buffer properties - * 03/10/2014 Martin Brampton Pointer arithmetic standard conformity - * Add more buffer handling macros - * Add gwbuf_rtrim (handle chains) - * 09/11/2014 Martin Brampton Add dprintAllBuffers (conditional compilation) - * - * @endverbatim */ #include @@ -186,33 +170,211 @@ typedef struct gwbuf /*< * Function prototypes for the API to maniplate the buffers */ -extern GWBUF *gwbuf_alloc(unsigned int size); -extern GWBUF *gwbuf_alloc_and_load(unsigned int size, const void *data); -extern void gwbuf_free(GWBUF *buf); -extern GWBUF *gwbuf_clone(GWBUF *buf); -extern GWBUF *gwbuf_append(GWBUF *head, GWBUF *tail); -extern GWBUF *gwbuf_consume(GWBUF *head, unsigned int length); -extern GWBUF *gwbuf_trim(GWBUF *head, unsigned int length); -extern GWBUF *gwbuf_rtrim(GWBUF *head, unsigned int length); -extern unsigned int gwbuf_length(GWBUF *head); -extern int gwbuf_count(GWBUF *head); -extern size_t gwbuf_copy_data(GWBUF *buffer, size_t offset, size_t bytes, - uint8_t* dest); -extern GWBUF *gwbuf_split(GWBUF **buf, size_t length); -extern GWBUF *gwbuf_clone_transform(GWBUF *head, gwbuf_type_t type); -extern void gwbuf_set_type(GWBUF *head, gwbuf_type_t type); -extern int gwbuf_add_property(GWBUF *buf, char *name, char *value); -extern char *gwbuf_get_property(GWBUF *buf, char *name); -extern GWBUF *gwbuf_make_contiguous(GWBUF *); -extern int gwbuf_add_hint(GWBUF *, HINT *); -void gwbuf_add_buffer_object(GWBUF* buf, - bufobj_id_t id, - void* data, - void (*donefun_fp)(void *)); -void* gwbuf_get_buffer_object_data(GWBUF* buf, bufobj_id_t id); +/** + * Allocate a new gateway buffer of specified size. + * + * @param size The size in bytes of the data area required + * + * @return Pointer to the buffer structure or NULL if memory could not + * be allocated. + */ +extern GWBUF *gwbuf_alloc(unsigned int size); + +/** + * Allocate a new gateway buffer structure of specified size and load with data. + * + * @param size The size in bytes of the data area required + * @param data Pointer to the data (size bytes) to be loaded + * + * @return Pointer to the buffer structure or NULL if memory could not + * be allocated. + */ +extern GWBUF *gwbuf_alloc_and_load(unsigned int size, const void *data); + +/** + * Free a chain of gateway buffers + * + * @param buf The head of the list of buffers to free + */ +extern void gwbuf_free(GWBUF *buf); + +/** + * Clone a GWBUF. Note that if the GWBUF is actually a list of + * GWBUFs, then every GWBUF in the list will be cloned. Note that but + * for the GWBUF structure itself, the data is shared. + * + * @param buf The GWBUF to be cloned. + * + * @return The cloned GWBUF, or NULL if @buf was NULL or if any part + * of @buf could not be cloned. + */ +extern GWBUF *gwbuf_clone(GWBUF *buf); + +/** + * Append a buffer onto a linked list of buffer structures. + * + * This call should be made with the caller holding the lock for the linked + * list. + * + * @param head The current head of the linked list + * @param tail The new buffer to make the tail of the linked list + * + * @return The new head of the linked list + */ +extern GWBUF *gwbuf_append(GWBUF *head, GWBUF *tail); + +/** + * @brief Consume data from buffer chain + * + * Data is consumed from @p head until either @p length bytes have been + * processed or @p head is empty. If @p head points to a chain of buffers, + * those buffers are counted as a part of @p head and will also be consumed if + * @p length exceeds the size of the first buffer. + * + * @param head The head of the linked list + * @param length Number of bytes to consume + * + * @return The head of the linked list or NULL if everything was consumed + */ +extern GWBUF *gwbuf_consume(GWBUF *head, unsigned int length); + +/** + * Trim bytes from the end of a GWBUF structure that may be the first + * in a list. If the buffer has n_bytes or less then it will be freed and + * the next buffer in the list will be returned, or if none, NULL. + * + * @param head The buffer to trim + * @param n_bytes The number of bytes to trim off + * + * @return The buffer chain or NULL if buffer chain now empty + */ +extern GWBUF *gwbuf_rtrim(GWBUF *head, unsigned int length); + +/** + * Return the number of bytes of data in the linked list. + * + * @param head The current head of the linked list + * + * @return The number of bytes of data in the linked list + */ +extern unsigned int gwbuf_length(const GWBUF *head); + +/** + * Return the number of individual buffers in the linked list. + * + * Currently not used, provided mainly for use during debugging sessions. + * + * @param head The current head of the linked list + * + * @return The number of bytes of data in the linked list + */ +extern int gwbuf_count(const GWBUF *head); + +/** + * @brief Copy bytes from a buffer + * + * Copy bytes from a chain of buffers. Supports copying data from buffers where + * the data is spread across multiple buffers. + * + * @param buffer Buffer to copy from + * @param offset Offset into the buffer + * @param bytes Number of bytes to copy + * @param dest Destination where the bytes are copied + * + * @return Number of bytes copied. + */ +extern size_t gwbuf_copy_data(const GWBUF *buffer, size_t offset, size_t bytes, uint8_t* dest); + +/** + * @brief Split a buffer in two + * + * The returned value will be @c length bytes long. If the length of @c buf + * exceeds @c length, the remaining buffers are stored in @buf. + * + * @param buf Buffer chain to split + * @param length Number of bytes that the returned buffer should contain + * + * @return Head of the buffer chain. + */ +extern GWBUF *gwbuf_split(GWBUF **buf, size_t length); + +/** + * Set given type to all buffers on the list. + * * + * @param buf The shared buffer + * @param type Type to be added + */ +extern void gwbuf_set_type(GWBUF *head, gwbuf_type_t type); + +/** + * Add a property to a buffer. + * + * @param buf The buffer to add the property to + * @param name The property name + * @param value The property value + * + * @return True on success, false otherwise. + */ +extern bool gwbuf_add_property(GWBUF *buf, char *name, char *value); + +/** + * Return the value of a buffer property + * + * @param buf The buffer itself + * @param name The name of the property to return + * + * @return The property value or NULL if the property was not found. + */ +extern char *gwbuf_get_property(GWBUF *buf, char *name); + +/** + * Convert a chain of GWBUF structures into a single GWBUF structure + * + * @param orig The chain to convert + * + * @return NULL if @c buf is NULL or if a memory allocation fails, + * @c buf if @c buf already is contiguous, and otherwise + * a contigious copy of @c buf. + * + * @attention If a non-NULL value is returned, the @c buf should no + * longer be used as it may have been freed. + */ +extern GWBUF *gwbuf_make_contiguous(GWBUF *buf); + +/** + * Add hint to a buffer. + * + * @param buf The buffer to add the hint to + * @param hint The hint. Note that the ownership of @c hint is transferred + * to @c buf. + */ +extern void gwbuf_add_hint(GWBUF *buf, HINT *hint); + +/** + * Add a buffer object to GWBUF buffer. + * + * @param buf GWBUF where object is added + * @param id Type identifier for object + * @param data Object data + * @param donefun_fp Clean-up function to be executed before buffer is freed. + */ +void gwbuf_add_buffer_object(GWBUF* buf, + bufobj_id_t id, + void* data, + void (*donefun_fp)(void *)); + +/** + * Search buffer object which matches with the id. + * + * @param buf GWBUF to be searched + * @param id Identifier for the object + * + * @return Searched buffer object or NULL if not found + */ +void *gwbuf_get_buffer_object_data(GWBUF* buf, bufobj_id_t id); #if defined(BUFFER_TRACE) -extern void dprintAllBuffers(void *pdcb); +extern void dprintAllBuffers(void *pdcb); #endif MXS_END_DECLS diff --git a/server/core/buffer.c b/server/core/buffer.c index abb484495..019b939df 100644 --- a/server/core/buffer.c +++ b/server/core/buffer.c @@ -11,32 +11,6 @@ * Public License. */ -/** - * @file buffer.h - The MaxScale buffer management functions - * - * The buffer management is based on the principle of a linked list - * of variable size buffer, the intention being to allow longer - * content to be buffered in a list and minimise any need to copy - * data between buffers. - * - * @verbatim - * Revision History - * - * Date Who Description - * 10/06/13 Mark Riddoch Initial implementation - * 11/07/13 Mark Riddoch Add reference count mechanism - * 16/07/2013 Massimiliano Pinto Added command type to gwbuf struct - * 24/06/2014 Mark Riddoch Addition of gwbuf_trim - * 15/07/2014 Mark Riddoch Addition of properties - * 28/08/2014 Mark Riddoch Adition of tail pointer to speed - * the gwbuf_append process - * 09/11/2015 Martin Brampton Add buffer tracing (conditional compilation), - * accessed by "show buffers" maxadmin command - * 20/12/2015 Martin Brampton Change gwbuf_free to free the whole list; add the - * gwbuf_count and gwbuf_alloc_and_load functions. - * - * @endverbatim - */ #include #include #include @@ -349,15 +323,6 @@ gwbuf_clone_one(GWBUF *buf) return rval; } -/** - * Clone a GWBUF. Note that if the GWBUF is actually a list of - * GWBUFs, then every GWBUF in the list will be cloned. - * - * @param buf The GWBUF to be cloned. - * - * @return The cloned GWBUF, or NULL if @buf was NULL or if any part - * of @buf could not be cloned. - */ GWBUF* gwbuf_clone(GWBUF* buf) { if (buf == NULL) @@ -422,16 +387,6 @@ static GWBUF *gwbuf_clone_portion(GWBUF *buf, return clonebuf; } -/** - * @brief Split a buffer in two - * - * The returned value will be @c length bytes long. If the length of @c buf - * exceeds @c length, the remaining buffers are stored in @buf. - * - * @param buf Buffer chain to split - * @param length Number of bytes that the returned buffer should contain - * @return Head of the buffer chain. - */ GWBUF* gwbuf_split(GWBUF **buf, size_t length) { GWBUF* head = NULL; @@ -484,66 +439,6 @@ GWBUF* gwbuf_split(GWBUF **buf, size_t length) return head; } -/** - * Returns pointer to GWBUF of a requested type. - * As of 10.3.14 only MySQL to plain text conversion is supported. - * Return NULL if conversion between types is not supported or due lacking - * type information. - */ -GWBUF *gwbuf_clone_transform(GWBUF *head, gwbuf_type_t targettype) -{ - gwbuf_type_t src_type; - GWBUF* clonebuf; - - CHK_GWBUF(head); - src_type = head->gwbuf_type; - - if (targettype == GWBUF_TYPE_UNDEFINED || - src_type == GWBUF_TYPE_UNDEFINED || - src_type == GWBUF_TYPE_PLAINSQL || - targettype == src_type) - { - clonebuf = NULL; - goto return_clonebuf; - } - - if (GWBUF_IS_TYPE_MYSQL(head)) - { - if (GWBUF_TYPE_PLAINSQL == targettype) - { - /** Crete reference to string part of buffer */ - clonebuf = gwbuf_clone_portion(head, - 5, - GWBUF_LENGTH(head) - 5); - ss_dassert(clonebuf != NULL); - /** Overwrite the type with new format */ - gwbuf_set_type(clonebuf, targettype); - } - else - { - clonebuf = NULL; - } - } - else - { - clonebuf = NULL; - } - -return_clonebuf: - return clonebuf; -} - - -/** - * Append a buffer onto a linked list of buffer structures. - * - * This call should be made with the caller holding the lock for the linked - * list. - * - * @param head The current head of the linked list - * @param tail The new buffer to make the tail of the linked list - * @return The new head of the linked list - */ GWBUF * gwbuf_append(GWBUF *head, GWBUF *tail) { @@ -562,18 +457,6 @@ gwbuf_append(GWBUF *head, GWBUF *tail) return head; } -/** - * @brief Consume data from buffer chain - * - * Data is consumed from @p head until either @p length bytes have been - * processed or @p head is empty. If @p head points to a chain of buffers, - * those buffers are counted as a part of @p head and will also be consumed if - * @p length exceeds the size of the first buffer. - * - * @param head The head of the linked list - * @param length Number of bytes to consume - * @return The head of the linked list or NULL if everything was consumed - */ GWBUF * gwbuf_consume(GWBUF *head, unsigned int length) { @@ -601,14 +484,8 @@ gwbuf_consume(GWBUF *head, unsigned int length) return head; } -/** - * Return the number of bytes of data in the linked list. - * - * @param head The current head of the linked list - * @return The number of bytes of data in the linked list - */ unsigned int -gwbuf_length(GWBUF *head) +gwbuf_length(const GWBUF *head) { int rval = 0; @@ -624,16 +501,8 @@ gwbuf_length(GWBUF *head) return rval; } -/** - * Return the number of individual buffers in the linked list. - * - * Currently not used, provided mainly for use during debugging sessions. - * - * @param head The current head of the linked list - * @return The number of bytes of data in the linked list - */ int -gwbuf_count(GWBUF *head) +gwbuf_count(const GWBUF *head) { int result = 0; while (head) @@ -644,41 +513,6 @@ gwbuf_count(GWBUF *head) return result; } -/** - * Trim bytes form the end of a GWBUF structure. If the - * buffer has n_bytes or less then it will be freed and - * NULL will be returned. - * - * This routine assumes the buffer is not part of a chain - * - * @param buf The buffer to trim - * @param n_bytes The number of bytes to trim off - * @return The buffer chain or NULL if buffer has <= n_bytes - */ -GWBUF * -gwbuf_trim(GWBUF *buf, unsigned int n_bytes) -{ - ss_dassert(buf->next == NULL); - - if (GWBUF_LENGTH(buf) <= n_bytes) - { - gwbuf_consume(buf, GWBUF_LENGTH(buf)); - return NULL; - } - buf->end = (void *)((char *)buf->end - n_bytes); - - return buf; -} - -/** - * Trim bytes from the end of a GWBUF structure that may be the first - * in a list. If the buffer has n_bytes or less then it will be freed and - * the next buffer in the list will be returned, or if none, NULL. - * - * @param head The buffer to trim - * @param n_bytes The number of bytes to trim off - * @return The buffer chain or NULL if buffer chain now empty - */ GWBUF * gwbuf_rtrim(GWBUF *head, unsigned int n_bytes) { @@ -695,15 +529,7 @@ gwbuf_rtrim(GWBUF *head, unsigned int n_bytes) return rval; } -/** - * Set given type to all buffers on the list. - * * - * @param buf The shared buffer - * @param type Type to be added - */ -void gwbuf_set_type( - GWBUF* buf, - gwbuf_type_t type) +void gwbuf_set_type(GWBUF* buf, gwbuf_type_t type) { /** Set type consistenly to all buffers on the list */ while (buf != NULL) @@ -714,14 +540,6 @@ void gwbuf_set_type( } } -/** - * Add a buffer object to GWBUF buffer. - * - * @param buf GWBUF where object is added - * @param id Type identifier for object - * @param data Object data - * @param donefun_fp Clean-up function to be executed before buffer is freed. - */ void gwbuf_add_buffer_object(GWBUF* buf, bufobj_id_t id, void* data, @@ -753,14 +571,6 @@ void gwbuf_add_buffer_object(GWBUF* buf, spinlock_release(&buf->gwbuf_lock); } -/** - * Search buffer object which matches with the id. - * - * @param buf GWBUF to be searched - * @param id Identifier for the object - * - * @return Searched buffer object or NULL if not found - */ void* gwbuf_get_buffer_object_data(GWBUF* buf, bufobj_id_t id) { buffer_object_t* bo; @@ -797,15 +607,7 @@ static buffer_object_t* gwbuf_remove_buffer_object(GWBUF* buf, buffer_object_t* return next; } -/** - * Add a property to a buffer. - * - * @param buf The buffer to add the property to - * @param name The property name - * @param value The property value - * @return Non-zero on success - */ -int +bool gwbuf_add_property(GWBUF *buf, char *name, char *value) { name = MXS_STRDUP(name); @@ -818,7 +620,7 @@ gwbuf_add_property(GWBUF *buf, char *name, char *value) MXS_FREE(name); MXS_FREE(value); MXS_FREE(prop); - return 0; + return false; } prop->name = name; @@ -827,15 +629,9 @@ gwbuf_add_property(GWBUF *buf, char *name, char *value) prop->next = buf->properties; buf->properties = prop; spinlock_release(&buf->gwbuf_lock); - return 1; + return true; } -/** - * Return the value of a buffer property - * @param buf The buffer itself - * @param name The name of the property to return - * @return The property value or NULL if the property was not found. - */ char * gwbuf_get_property(GWBUF *buf, char *name) { @@ -855,13 +651,6 @@ gwbuf_get_property(GWBUF *buf, char *name) return NULL; } - -/** - * Convert a chain of GWBUF structures into a single GWBUF structure - * - * @param orig The chain to convert - * @return The contiguous buffer - */ GWBUF * gwbuf_make_contiguous(GWBUF *orig) { @@ -895,14 +684,7 @@ gwbuf_make_contiguous(GWBUF *orig) return newbuf; } -/** - * Add hint to a buffer. - * - * @param buf The buffer to add the hint to - * @param hint The hint itself - * @return Non-zero on success - */ -int +void gwbuf_add_hint(GWBUF *buf, HINT *hint) { HINT *ptr; @@ -922,22 +704,9 @@ gwbuf_add_hint(GWBUF *buf, HINT *hint) buf->hint = hint; } spinlock_release(&buf->gwbuf_lock); - return 1; } -/** - * @brief Copy bytes from a buffer - * - * Copy bytes from a chain of buffers. Supports copying data from buffers where - * the data is spread across multiple buffers. - * - * @param buffer Buffer to copy from - * @param offset Offset into the buffer - * @param bytes Number of bytes to copy - * @param dest Destination where the bytes are copied - * @return Number of bytes copied - */ -size_t gwbuf_copy_data(GWBUF *buffer, size_t offset, size_t bytes, uint8_t* dest) +size_t gwbuf_copy_data(const GWBUF *buffer, size_t offset, size_t bytes, uint8_t* dest) { uint32_t buflen; diff --git a/server/core/test/testbuffer.c b/server/core/test/testbuffer.c index 92ed91d00..849711560 100644 --- a/server/core/test/testbuffer.c +++ b/server/core/test/testbuffer.c @@ -323,7 +323,7 @@ void test_consume() static int test1() { - GWBUF *buffer, *extra, *clone, *partclone, *transform; + GWBUF *buffer, *extra, *clone, *partclone; HINT *hint; int size = 100; int bite1 = 35; @@ -357,16 +357,6 @@ test1() strcpy((char*)GWBUF_DATA(buffer), "1234\x03SELECT * FROM sometable"); ss_dfprintf(stderr, "\t..done\nLoad SQL data into the buffer"); ss_info_dassert(1 == GWBUF_IS_SQL(buffer), "Must say buffer is SQL, as it does have marker"); - transform = gwbuf_clone_transform(buffer, GWBUF_TYPE_PLAINSQL); - ss_dfprintf(stderr, "\t..done\nAttempt to transform buffer to plain SQL - should fail"); - ss_info_dassert(NULL == transform, "Buffer cannot be transformed to plain SQL"); - gwbuf_set_type(buffer, GWBUF_TYPE_MYSQL); - ss_dfprintf(stderr, "\t..done\nChanged buffer type to MySQL"); - ss_info_dassert(GWBUF_IS_TYPE_MYSQL(buffer), "Buffer type changed to MySQL"); - transform = gwbuf_clone_transform(buffer, GWBUF_TYPE_PLAINSQL); - ss_dfprintf(stderr, "\t..done\nAttempt to transform buffer to plain SQL - should succeed"); - ss_info_dassert((NULL != transform) && - (GWBUF_IS_TYPE_PLAINSQL(transform)), "Transformed buffer is plain SQL"); clone = gwbuf_clone(buffer); ss_dfprintf(stderr, "\t..done\nCloned buffer"); buflen = GWBUF_LENGTH(clone);