mysql map数据结构_MySQL数据结构分析

目的

MySQL数据结构Vio是MySQL对网络通信底层的进行封装结构,是MySQL网络通信数据结构NET重要的成员变量。Vio数据结构的封装,屏蔽了跨平台的差异性、统一了不同读写策略的接口等。使得网络通信过程可以不考虑具体实现的细节,而仅考虑算法和处理逻辑,从而处理MySQL的通信。

数据结构

MySQL数据结构Vio的定义在源码中/include/violate.h和/vio/vio_priv.h,具体定义如下所示:

enum enum_vio_type

{

VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET, VIO_TYPE_NAMEDPIPE,

VIO_TYPE_SSL, VIO_TYPE_SHARED_MEMORY

};

/* This structure is for every connection on both sides */

struct st_vio

{

my_socket sd; /* my_socket - real or imaginary */

HANDLE hPipe;

my_bool localhost; /* Are we from localhost? */

int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */

struct sockaddr_storage local; /* Local internet address */

struct sockaddr_storage remote; /* Remote internet address */

int addrLen; /* Length of remote address */

enum enum_vio_type type; /* Type of connection */

char desc[30]; /* String description */

char *read_buffer; /* buffer for vio_read_buff */

char *read_pos; /* start of unfetched data in the read buffer */

char *read_end; /* end of unfetched data */

/* function pointers. They are similar for socket/SSL/whatever */

void (*viodelete)(Vio*);

int (*vioerrno)(Vio*);

size_t (*read)(Vio*, uchar *, size_t);

size_t (*write)(Vio*, const uchar *, size_t);

int (*vioblocking)(Vio*, my_bool, my_bool *);

my_bool (*is_blocking)(Vio*);

int (*viokeepalive)(Vio*, my_bool);

int (*fastsend)(Vio*);

my_bool (*peer_addr)(Vio*, char *, uint16*, size_t);

void (*in_addr)(Vio*, struct sockaddr_storage*);

my_bool (*should_retry)(Vio*);

my_bool (*was_interrupted)(Vio*);

int (*vioclose)(Vio*);

void (*timeout)(Vio*, unsigned int which, unsigned int timeout);

my_bool (*poll_read)(Vio *vio, uint timeout);

my_bool (*is_connected)(Vio*);

my_bool (*has_data) (Vio*);

#ifdef HAVE_OPENSSL

void *ssl_arg;

#endif

#ifdef HAVE_SMEM

HANDLE handle_file_map;

char *handle_map;

HANDLE event_server_wrote;

HANDLE event_server_read;

HANDLE event_client_wrote;

HANDLE event_client_read;

HANDLE event_conn_closed;

size_t shared_memory_remain;

char *shared_memory_pos;

#endif /* HAVE_SMEM */

#ifdef _WIN32

OVERLAPPED pipe_overlapped;

DWORD read_timeout_ms;

DWORD write_timeout_ms;

#endif

};

typedef struct st_vio Vio;

枚举类型enum_vio_type定义了Vio的几种不同的网络连接类型,根据不同的类型,在网络通信时有相应不同的处理逻辑。

Vio数据结构的定义分为几个部分:成员变量部分、接口部分、SSL部分、共享内存部分和windows特有成员变量。其中成员变量包括:socket描述符sd;管道描述符hPipe;localhost表示是否为本机;fcntl_mode表示socket文件描述符的模式,通过fcntl()函数(在windows下是fcntlsocket()函数)设置sd描述符的一些特性;local和remote分别表示本地和远端的网络地址,其中sockaddr_storage是通用网络地址数据结构;addrLen远端的网络地址长度;type表示网络连接类型;数组desc是Vio的描述信息;read_buffer、read_pos、read_end分别表示读buffer缓冲的指针地址、读取的当前位置以及结束地址,socket数据读取采用缓冲机制,提高读的性能。接口部分是socket的基本操作的函数指针,根据不同的平台和不同的读写策略,分别指向不同的处理函数。SSL部分是指当定义了HAVE_OPENSSL宏时,定义SSL相关的成员变量ssl_arg。共享内存部分是指当定义了HAVE_SMEM宏时,定义共享内存相关的成员变量。如果定义了_WIN32宏时,那么需要定义windows操作的成员变量。SSL部分、共享内存部分和windows特有成员变量都是根据编译时定义的宏及平台决定的,是不同读写策略时,使用的成员变量。

源码实现

MySQL数据结构Vio对网络通信的封转,在源码的/vio/vio.c、/vio/viosocket.c、/vio/viossl.c、/vio/viosslfactories.c中实现。由于大多数的实现是根据不同的连接类型,对底层函数的调用,基本不涉及复杂的算法和处理逻辑。因此,以下内容中,仅对几个比较核心的处理过程进行简要的分析。

vio_init函数

vio_init()函数是Vio的内部初始化函数,对外接口vio_new*()初始化函数,都调用vio_init()函数进行初始化。该函数根据不同的连接类型,初始化相应类型的处理函数指针。参考源码/vio/vio.c。

vio_read_buffer函数

vio_read_buffer()函数是网络缓冲写方法,该方法同IO_CACHE的io读有相似之处。读取策略分为三种:如果read_buffer中有数据,直接从read_buffer中读取数据;如果读取的数据长度小于16K,那么调用vio_read()函数读取16K数据到read_buffer中,然后再从read_buffer中读取数据;如果数据长度大于16K,直接通过vio_read()读取制定长度的数据,不需要写入缓冲read_buffer。这种读写策略,可以有效的提高小数据量读取的性能。例如readline这种方式,需要通过逐个字符判断是否为换行符,如果直接调用vio_read()进行读取,会每次产生一次寻址、读取等物理操作。而采用缓冲读策略,所有的操作从read_buffer中获取数据,避免频繁的物理操作。

vio_close函数

vio_close()函数是关闭网络连接的操作,在该过程中,有一个问题需要特别说明。在调用close()(windows下使用closesocket()函数)进行关闭socket连接之前,调用shutdown()函数将读写关闭。这是因为,在多个进程共享一个socket套接字,调用close()只是引用数减1,其他进程仍然可以通信,直到计数为0,才将socket套接字释放。而调用shutdown(2)则使得其他进程也无法进行通信。具体close()[1]和shutdown()[2]的区别,可以参考Linux manual中相应的解释。

socket_poll_read函数

socket_poll_read()函数是实现IO复用的封装函数,从该封装函数中可以看出,MySQL在IO复用中,如果操作系统是windows,那么采用select()函数(在linux下select()的最大文件描述数目为1024,windows下无限制),在Linux系统中,使用poll()函数。select()和poll()类似,性能比select()略高。然而,这两种方式都存在一个问题,因为他们都需要遍历所有的文件描述符,当监听描述符个数增加时,监听效率降低,并且select和poll每次都要在用户态和内核态拷贝监听的描述符参数。更为高效的解决方案是epoll()方法,可以解决select()和poll()存在的不足。具体详细的分析和差异,参考相应的文档。

SSL相关的处理函数在源码的/vio/viossl.c和/vio/viosslfactories.c,具体的实现主要是对SSL相关函数的封装,不再赘述。

结论

通过以上分析可知,MySQL数据结构Vio主要封装了不同连接方式的网络通信接口,从而使得网络通信可以忽略平台差异和连接方式的不同,并且可以支持共享内存、SSL安全连接方式等通信方式。

然而在IO复用方面,MySQL数据结构Vio存在一定的不足,使用了poll()方式。对于数据库这种高并发系统来说,会随着连接数的增加,使得poll()的系统调用次数严重下降,处理能力也随之降低。因此,对MySQL来说,一般的优化方案是限制连接数,而在应用层使用连接池的策略,来解决这个问题。然而当多个不同系统同时使用一个数据库实例时,仍然会导致连接数增加,如果该值设置较小的话,会导致连接失败。最佳的方式是使用epoll()方式代替poll()方式,从本质上提高处理能力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值