在Windows平台下,MySQL可以使用三种方式和客户单通信。分别是套接字(SOCKET)、管道(Pipe)、共享内存(ShareMemory).
而到底使用哪种方式,MySQL在编译的时候就已经决定了,在vio.c文件中会对通信方式进行初始化(vio_init函数,见后面),而对于不同类型的通信方式肯定会有不同的函数定义了,这些指针函数就定义在viosocket.c当中。这其中又有连个函数吸引我注意的,因为一开始我没有理解是什么意思(见后面代码中注释 )。
/*
* Helper to fill most of the Vio* with defaults.
*/
static void vio_init(Vio* vio, enum enum_vio_type type,
my_socket sd, HANDLE hPipe, uint flags)
{
DBUG_ENTER("vio_init");
DBUG_PRINT("enter", ("type: %d sd: %d flags: %d", type, sd, flags));
#ifndef HAVE_VIO_READ_BUFF
flags&= ~VIO_BUFFERED_READ;
#endif
bzero((char*) vio, sizeof(*vio));
vio->type = type;
vio->sd = sd;
vio->hPipe = hPipe;
vio->localhost= flags & VIO_LOCALHOST;
if ((flags & VIO_BUFFERED_READ) &&
!(vio->read_buffer= (char*)my_malloc(VIO_READ_BUFFER_SIZE, MYF(MY_WME))))
flags&= ~VIO_BUFFERED_READ;
#ifdef _WIN32
if (type == VIO_TYPE_NAMEDPIPE)
{
vio->viodelete =vio_delete;
此处省略N个字
vio->timeout=vio_win32_timeout;
/* Set default timeout */
vio->read_timeout_ms= INFINITE;
vio->write_timeout_ms= INFINITE;
vio->pipe_overlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL);
DBUG_VOID_RETURN;
}
#endif
#ifdef HAVE_SMEM
if (type == VIO_TYPE_SHARED_MEMORY)
{
vio->viodelete =vio_delete;
vio->vioerrno =vio_errno;
vio->read =vio_read_shared_memory;
vio->write =vio_write_shared_memory;
vio->fastsend =vio_fastsend;
此处省略N个字
vio->has_data =has_no_data;
/* Currently, shared memory is on Windows only, hence the below is ok*/
vio->timeout= vio_win32_timeout;
/* Set default timeout */
vio->read_timeout_ms= INFINITE;
vio->write_timeout_ms= INFINITE;
DBUG_VOID_RETURN;
}
#endif
#ifdef HAVE_OPENSSL
if (type == VIO_TYPE_SSL)
{
vio->viodelete =vio_ssl_delete;
vio->vioerrno =vio_errno;
vio->read =vio_ssl_read;
此处省略N个字
vio->has_data =vio_ssl_has_data;
DBUG_VOID_RETURN;
}
#endif /* HAVE_OPENSSL */
vio->viodelete =vio_delete;
此处省略N个字
vio->is_connected =vio_is_connected;
vio->has_data= (flags & VIO_BUFFERED_READ) ?
vio_buff_has_data : has_no_data;
DBUG_VOID_RETURN;
}
这连个函数就是网络读取函数:
size_t vio_read(Vio * vio, uchar* buf, size_t size)
{
size_t r;
DBUG_ENTER("vio_read");
DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %u", vio->sd, (long) buf,
(uint) size));
/* Ensure nobody uses vio_read_buff and vio_read simultaneously */
DBUG_ASSERT(vio->read_end == vio->read_pos);
#ifdef __WIN__
r = recv(vio->sd, buf, size,0);
#else
errno=0; /* For linux */
r = read(vio->sd, buf, size);
#endif /* __WIN__ */
#ifndef DBUG_OFF
if (r == (size_t) -1)
{
DBUG_PRINT("vio_error", ("Got error %d during read",errno));
}
#endif /* DBUG_OFF */
DBUG_PRINT("exit", ("%ld", (long) r));
DBUG_RETURN(r);
}
/*
Buffered read: if average read size is small it may
reduce number of syscalls.
*/
size_t vio_read_buff(Vio *vio, uchar* buf, size_t size)
{
size_t rc;
#define VIO_UNBUFFERED_READ_MIN_SIZE 2048
DBUG_ENTER("vio_read_buff");
DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %u", vio->sd, (long) buf,
(uint) size));
if (vio->read_pos < vio->read_end)
{
rc= min((size_t) (vio->read_end - vio->read_pos), size);
memcpy(buf, vio->read_pos, rc);
vio->read_pos+= rc;
/*
Do not try to read from the socket now even if rc < size:
vio_read can return -1 due to an error or non-blocking mode, and
the safest way to handle it is to move to a separate branch.
*/
}
else if (size < VIO_UNBUFFERED_READ_MIN_SIZE)
{
rc= vio_read(vio, (uchar*) vio->read_buffer, VIO_READ_BUFFER_SIZE);
if (rc != 0 && rc != (size_t) -1)
{
if (rc > size)
{
vio->read_pos= vio->read_buffer + size;
vio->read_end= vio->read_buffer + rc;
rc= size;
}
memcpy(buf, vio->read_buffer, rc);
}
}
else
rc= vio_read(vio, buf, size);
DBUG_RETURN(rc);
#undef VIO_UNBUFFERED_READ_MIN_SIZE
}
从中可以看出,使用缓存的话,可以缓存VIO_READ_BUFFER_SIZE多个字符,意思是避免小的读取可以直接在缓存中读取。只看此处我认为如果当缓存中还有数据,而要读取的数据大于缓存中数据的时候,此处只返回了缓存中的数据。而如果此时其实套接自上是有数据的呢。
要知此处究竟,还须继续努力地看了。
其他的管道、共享内存应该是同样的处理方式了,我也没有去看,先走通一遍吧