Conflicts: server/core/dcb.c server/modules/include/blr.h server/modules/routing/binlog/STATUS server/modules/routing/binlog/blr.c server/modules/routing/binlog/blr_file.c server/modules/routing/binlog/blr_master.c server/modules/routing/binlog/blr_slave.c
		
			
				
	
	
		
			328 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			328 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * This file is distributed as part of the SkySQL Gateway.  It is free
 | 
						|
 * software: you can redistribute it and/or modify it under the terms of the
 | 
						|
 * GNU General Public License as published by the Free Software Foundation,
 | 
						|
 * version 2.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
						|
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | 
						|
 * details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License along with
 | 
						|
 * this program; if not, write to the Free Software Foundation, Inc., 51
 | 
						|
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
						|
 *
 | 
						|
 * Copyright SkySQL Ab 2013
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * @file buffer.h  - The Gateway buffer management functions
 | 
						|
 *
 | 
						|
 * The buffer management is based on the principle of a linked list
 | 
						|
 * of variable size buffer, the intention beign 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
 | 
						|
 *
 | 
						|
 * @endverbatim
 | 
						|
 */
 | 
						|
#include <stdlib.h>
 | 
						|
#include <buffer.h>
 | 
						|
#include <atomic.h>
 | 
						|
#include <skygw_debug.h>
 | 
						|
 | 
						|
/**
 | 
						|
 * Allocate a new gateway buffer structure of size bytes.
 | 
						|
 *
 | 
						|
 * For now we allocate memory directly from malloc for buffer the management
 | 
						|
 * structure and the actual data buffer itself. We may swap at a future date
 | 
						|
 * to a more effecient mechanism.
 | 
						|
 *
 | 
						|
 * @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.
 | 
						|
 */
 | 
						|
GWBUF	*
 | 
						|
gwbuf_alloc(unsigned int size)
 | 
						|
{
 | 
						|
GWBUF		*rval;
 | 
						|
SHARED_BUF	*sbuf;
 | 
						|
 | 
						|
	// Allocate the buffer header
 | 
						|
	if ((rval = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
 | 
						|
	{
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	// Allocate the shared data buffer
 | 
						|
	if ((sbuf = (SHARED_BUF *)malloc(sizeof(SHARED_BUF))) == NULL)
 | 
						|
	{
 | 
						|
		free(rval);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	// Allocate the space for the actual data
 | 
						|
	if ((sbuf->data = (unsigned char *)malloc(size)) == NULL)
 | 
						|
	{
 | 
						|
		free(rval);
 | 
						|
		free(sbuf);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	rval->start = sbuf->data;
 | 
						|
	rval->end = rval->start + size;
 | 
						|
	sbuf->refcount = 1;
 | 
						|
	rval->sbuf = sbuf;
 | 
						|
	rval->next = NULL;
 | 
						|
        rval->gwbuf_type = GWBUF_TYPE_UNDEFINED;
 | 
						|
	rval->command = 0;
 | 
						|
        CHK_GWBUF(rval);
 | 
						|
	return rval;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Free a gateway buffer
 | 
						|
 *
 | 
						|
 * @param buf The buffer to free
 | 
						|
 */
 | 
						|
void
 | 
						|
gwbuf_free(GWBUF *buf)
 | 
						|
{
 | 
						|
	CHK_GWBUF(buf);
 | 
						|
	if (atomic_add(&buf->sbuf->refcount, -1) == 1)
 | 
						|
	{
 | 
						|
                free(buf->sbuf->data);
 | 
						|
                free(buf->sbuf);
 | 
						|
	}
 | 
						|
	free(buf);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Increment the usage count of a gateway buffer. This gets a new
 | 
						|
 * GWBUF structure that shares the actual data with the existing
 | 
						|
 * GWBUF structure but allows for the data copy to be avoided and
 | 
						|
 * also for each GWBUF to point to different portions of the same
 | 
						|
 * SHARED_BUF.
 | 
						|
 *
 | 
						|
 * @param buf The buffer to use
 | 
						|
 * @return A new GWBUF structure
 | 
						|
 */
 | 
						|
GWBUF *
 | 
						|
gwbuf_clone(GWBUF *buf)
 | 
						|
{
 | 
						|
GWBUF	*rval;
 | 
						|
 | 
						|
	if ((rval = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
 | 
						|
	{
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	atomic_add(&buf->sbuf->refcount, 1);
 | 
						|
	rval->sbuf = buf->sbuf;
 | 
						|
	rval->start = buf->start;
 | 
						|
	rval->end = buf->end;
 | 
						|
        rval->gwbuf_type = buf->gwbuf_type;
 | 
						|
	rval->next = NULL;
 | 
						|
        CHK_GWBUF(rval);
 | 
						|
	return rval;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
GWBUF *gwbuf_clone_portion(
 | 
						|
        GWBUF *buf,
 | 
						|
        size_t start_offset,
 | 
						|
        size_t length)
 | 
						|
{
 | 
						|
        GWBUF* clonebuf;
 | 
						|
        
 | 
						|
        CHK_GWBUF(buf);
 | 
						|
        ss_dassert(start_offset+length <= GWBUF_LENGTH(buf));
 | 
						|
        
 | 
						|
        if ((clonebuf = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
 | 
						|
        {
 | 
						|
                return NULL;
 | 
						|
        }
 | 
						|
        atomic_add(&buf->sbuf->refcount, 1);
 | 
						|
        clonebuf->sbuf = buf->sbuf;
 | 
						|
        clonebuf->start = (void *)((char*)buf->start)+start_offset;
 | 
						|
        clonebuf->end = (void *)((char *)clonebuf->start)+length;
 | 
						|
        clonebuf->gwbuf_type = buf->gwbuf_type; /*< clone the type for now */ 
 | 
						|
        clonebuf->next = NULL;
 | 
						|
        CHK_GWBUF(clonebuf);
 | 
						|
        return clonebuf;
 | 
						|
        
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 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;
 | 
						|
        }
 | 
						|
 | 
						|
        switch (src_type)
 | 
						|
        {
 | 
						|
                case GWBUF_TYPE_MYSQL:
 | 
						|
                        if (targettype == GWBUF_TYPE_PLAINSQL)
 | 
						|
                        {
 | 
						|
                                /** 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 */
 | 
						|
                                clonebuf->gwbuf_type = targettype;
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                                clonebuf = NULL;
 | 
						|
                        }
 | 
						|
                        break;
 | 
						|
                        
 | 
						|
                default:
 | 
						|
                        clonebuf = NULL;
 | 
						|
                        break;                        
 | 
						|
        } /*< switch (src_type) */
 | 
						|
        
 | 
						|
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)
 | 
						|
{
 | 
						|
GWBUF	*ptr = head;
 | 
						|
        
 | 
						|
	if (!head)
 | 
						|
		return tail;
 | 
						|
        CHK_GWBUF(head);
 | 
						|
        CHK_GWBUF(tail);
 | 
						|
	while (ptr->next)
 | 
						|
	{
 | 
						|
		ptr = ptr->next;
 | 
						|
	}
 | 
						|
	ptr->next = tail;
 | 
						|
	return head;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Consume data from a buffer in the linked list. The assumption is to consume
 | 
						|
 * n bytes from the buffer chain.
 | 
						|
 *
 | 
						|
 * If after consuming the bytes from the first buffer that buffer becomes
 | 
						|
 * empty it will be freed and the linked list updated.
 | 
						|
 *
 | 
						|
 * The return value is the new head of the linked list.
 | 
						|
 *
 | 
						|
 * This call should be made with the caller holding the lock for the linked
 | 
						|
 * list.
 | 
						|
 *
 | 
						|
 * @param head		The head of the linked list
 | 
						|
 * @param length	The amount of data to consume
 | 
						|
 * @return The head of the linked list
 | 
						|
 */
 | 
						|
GWBUF *
 | 
						|
gwbuf_consume(GWBUF *head, unsigned int length)
 | 
						|
{
 | 
						|
GWBUF *rval = head;
 | 
						|
 | 
						|
        CHK_GWBUF(head);
 | 
						|
	GWBUF_CONSUME(head, length);
 | 
						|
        CHK_GWBUF(head);
 | 
						|
        
 | 
						|
	if (GWBUF_EMPTY(head))
 | 
						|
	{
 | 
						|
		rval = head->next;
 | 
						|
		gwbuf_free(head);
 | 
						|
	}
 | 
						|
 | 
						|
	ss_dassert(rval->end > rval->start);
 | 
						|
 | 
						|
	return rval;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 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)
 | 
						|
{
 | 
						|
int	rval = 0;
 | 
						|
 | 
						|
	if (head)
 | 
						|
	{
 | 
						|
	        CHK_GWBUF(head);
 | 
						|
	}
 | 
						|
	while (head)
 | 
						|
	{
 | 
						|
		rval += GWBUF_LENGTH(head);
 | 
						|
		head = head->next;
 | 
						|
	}
 | 
						|
	return rval;
 | 
						|
}
 | 
						|
 | 
						|
bool gwbuf_set_type(
 | 
						|
        GWBUF*       buf,
 | 
						|
        gwbuf_type_t type)
 | 
						|
{
 | 
						|
        bool succp;
 | 
						|
        CHK_GWBUF(buf);
 | 
						|
        
 | 
						|
        switch (type) {
 | 
						|
                case GWBUF_TYPE_MYSQL:
 | 
						|
                case GWBUF_TYPE_PLAINSQL:
 | 
						|
                case GWBUF_TYPE_UNDEFINED:
 | 
						|
                        buf->gwbuf_type = type;
 | 
						|
                        succp = true;
 | 
						|
                        break;
 | 
						|
                default:
 | 
						|
                        succp = false;
 | 
						|
                        break;
 | 
						|
        }
 | 
						|
        ss_dassert(succp);
 | 
						|
        return succp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 |