首页 > 数据库 >postgresql socket读数据返回-1

postgresql socket读数据返回-1

时间:2024-01-03 13:02:20浏览次数:37  
标签:返回 postgresql socket read 阻塞 读数据 write wait

如下所示:

{
        n = secure_raw_read(port, ptr, len);   // pg的socket读是非阻塞读,所以返回-1不影响,后面等到socket可读之后继续读。见下文socket返回值解释
        waitfor = WL_SOCKET_READABLE;
    }

    /* In blocking mode, wait until the socket is ready */
    if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))   // 非阻塞读,且errono==EAGAIN,所以就是每次处理完一个SQL语句后,会继续读下一个SQL,发现读不到,进到这里,通过latch设置等待客户端可读事件
    {
        WaitEvent    event;

        Assert(waitfor);

        ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);

        WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
                         WAIT_EVENT_CLIENT_READ);

        /*
         * If the postmaster has died, it's not safe to continue running,
         * because it is the postmaster's job to kill us if some other backend
         * exits uncleanly.  Moreover, we won't run very well in this state;
         * helper processes like walwriter and the bgwriter will exit, so
         * performance may be poor.  Finally, if we don't exit, pg_ctl will be
         * unable to restart the postmaster without manual intervention, so no
         * new connections can be accepted.  Exiting clears the deck for a
         * postmaster restart.
         *
         * (Note that we only make this check when we would otherwise sleep on
         * our latch.  We might still continue running for a while if the
         * postmaster is killed in mid-query, or even through multiple queries
         * if we never have to wait for read.  We don't want to burn too many
         * cycles checking for this very rare condition, and this should cause
         * us to exit quickly in most cases.)
         */
        if (event.events & WL_POSTMASTER_DEATH)
            ereport(FATAL,
                    (errcode(ERRCODE_ADMIN_SHUTDOWN),
                     errmsg("terminating connection due to unexpected postmaster exit")));

        /* Handle interrupt. */
        if (event.events & WL_LATCH_SET)
        {
            ResetLatch(MyLatch);
            ProcessClientReadInterrupt(true);

            /*
             * We'll retry the read. Most likely it will return immediately
             * because there's still no data available, and we'll wait for the
             * socket to become ready again.
             */
        }
        goto retry;
    }

在底层,linux内核 4.x平台中,等待socket可读是通过epoll_wait实现的。

#0  0x00007fa94fd880bb in epoll_wait () from /lib64/libc.so.6
#1  0x00000000007916de in WaitEventSetWaitBlock (nevents=1, occurred_events=0x7fffb042fd40, cur_timeout=-1, set=0x2bf7e58) at latch.c:1295
#2  WaitEventSetWait (set=0x2bf7e58, timeout=timeout@entry=-1, occurred_events=occurred_events@entry=0x7fffb042fd40, nevents=nevents@entry=1, wait_event_info=wait_event_info@entry=100663296) at latch.c:1247
#3  0x0000000000688233 in secure_read (port=0x2c5b970, ptr=0xdc7500 <PqRecvBuffer>, len=8192) at be-secure.c:184
#4  0x000000000068eb7b in pq_recvbuf () at pqcomm.c:947
#5  pq_recvbuf () at pqcomm.c:923
#6  0x000000000068f985 in pq_getbyte () at pqcomm.c:990
#7  0x00000000007b531e in SocketBackend (inBuf=0x7fffb042ff40) at postgres.c:357
#8  ReadCommand (inBuf=0x7fffb042ff40) at postgres.c:530
#9  PostgresMain (argc=<optimized out>, argv=argv@entry=0x2c64490, dbname=<optimized out>, username=<optimized out>) at postgres.c:4598
#10 0x000000000073549d in BackendRun (port=0x2c5b970, port=0x2c5b970) at postmaster.c:5063

3.x内核版本中我记得是poll而非poll。

socket读写返回不同值的总结

在调用socket读写函数read(),write()时,都会有返回值。如果没有正确处理返回值,就可能引入一些问题

1当read()或者write()函数返回值大于0时,表示实际从缓冲区读取或者写入的字节数目

2当read()函数返回值为0时,表示对端已经关闭了 socket,这时候也要关闭这个socket,否则会导致socket泄露。netstat命令查看下,如果有closewait状态的socket,就是socket泄露了

当write()函数返回0时,表示当前写缓冲区已满,是正常情况,下次再来写就行了。

3当read()或者write()返回-1时,一般要判断errno

如果errno == EINTR,表示系统当前中断了,直接忽略

如果errno == EAGAIN或者EWOULDBLOCK,非阻塞socket直接忽略;如果是阻塞的socket,一般是读写操作超时了,还未返回。这个超时是指socket的SO_RCVTIMEO与SO_SNDTIMEO两个属性。所以在使用阻塞socket时,不要将超时时间设置的过小。不然返回了-1,你也不知道是socket连接是真的断开了,还是正常的网络抖动。一般情况下,阻塞的socket返回了-1,都需要关闭重新连接。

4.另外,对于非阻塞的connect,可能返回-1.这时需要判断errno,如果 errno == EINPROGRESS,表示正在处理中,否则表示连接出错了,需要关闭重连。之后使用select,检测到该socket的可写事件时,要判断getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen),看socket是否出错了。如果err值为0,则表示connect成功;否则也应该关闭重连

5 在使用epoll时,有ET与LT两种模式。ET模式下,socket需要read或者write到返回-1为止。对于非阻塞的socket没有问题,但是如果是阻塞的socket,正如第三条中所说的,只有超时才会返回。所以在ET模式下千万不要使用阻塞的socket。那么LT模式为什么没问题呢?一般情况下,使用LT模式,我们只要调用一次read或者write函数,如果没有读完或者没有写完,下次再来就是了。由于已经返回了可读或者可写事件,所以可以保证调用一次read或者write会正常返回。

注:除了read/write外,send/recv也可以读写socket,差别是多了个选项,但是在pg中用的是send/recv,第四个选项标志位均没有使用。第四个标志位的含义可以参考。 

标签:返回,postgresql,socket,read,阻塞,读数据,write,wait
From: https://blog.51cto.com/zhjh256/9082340

相关文章

  • windows下logstash从文件中读数据写入es报错 Error: No such file or directory - :/d
    [2023-12-22T17:26:50,327][ERROR][logstash.javapipeline][main][897a6c7006446c97daa2ee44df7541701882ceece289ce428fcfac8aa982a0c5]Apluginhadanunrecoverableerror.Willrestartthisplugin.Pipeline_id:mainPlugin:<LogStash::Inputs::Filestar......
  • 如何在PostgreSQL中管理锁定的表和进程
    在使用PostgreSQL数据库时,可能会遇到一种情况:某些进程锁定了特定的表,影响了数据库的正常操作。这时,了解如何查找并管理这些锁定进程是非常重要的。下面是一些步骤和注意事项,帮助您处理这种情况。步骤1:查找锁定的表和进程首先,您需要确定哪些进程正在锁定您关心的表。可以通过以下SQL......
  • 使用 PostgreSQL 16.1 + Citus 12.1 作为多个微服务的分布式 Sharding 存储后端
    在本教程中,我们将使用PostgreSQL16.1+Citus12.1作为多个微服务的存储后端,演示此类集群的样例设置和基本操作。Citus12.1实验环境设置Docker快速启动Citus分布式集群docker-compose.ymlversion:"3"services:master:container_name:"${COMPOSE_PROJECT_NAME:......
  • Linux内核socket系统调用源码分析
    一、环境说明内核版本:Linux3.10内核源码地址:https://elixir.bootlin.com/linux/v3.10/source(包含各个版本内核源码,且网页可全局搜索函数)二、应用层-socket()函数应用层创建socket对象返回整型的文件描述符。/*family:被称为协议族,或者协议域。*type:套接字类型。*......
  • MAC下载MySQL5.7:Can't connect to local MySQL server through socket '/tmp/mysql.so
    1.错误描述错误截图如下所示:3.扩展MySQL服务启动、关闭、重启命令:启动MySQL服务:sudo/usr/local/mysql/support-files/mysql.serverstart停止MySQL服务:sudo/usr/local/mysql/support-files/mysql.serverstop重启MySQL服务:sudo/usr/local/mysql/support-files/mysql.serverr......
  • PHP 之phpsocket.io简易聊天室
    一、安装composerrequireworkerman/phpsocket.io二、服务端和客户端连接<?phprequire_once'./vendor/autoload.php';useWorkerman\Worker;usePHPSocketIO\SocketIO;$io=newSocketIO(3120);//当有客户端连接时$io->on('connection',function($s......
  • socket addr赋值
    #include<iostream>#include<string>usingnamespacestd;#include<stdint.h>#include<stdio.h>#include<stdlib.h>#include<memory.h>#include<sys/socket.h>#include<netinet/in.h>#include<sys/soc......
  • OpenEuler22.03安装PostgreSQL15.5并配置一主二从
    环境准备序号IP标识(hostname)CPU/内存配置系统盘数据盘1192.168.8.190pg018C+16G80G500G2192.168.8.191pg028C+16G80G500G3192.168.8.192pg038C+16G80G500G规划的文件夹目录(所有主机):##以下目录为本文规划的目录,可以提前创建,也可以跟着......
  • 安卓日志系统(logcat / liblog / logd) 跨进程通信的消耗:日志信息通过socket 发送到 lo
    深入理解安卓日志系统(logcat/liblog/logd)-掘金https://juejin.cn/post/6905368512001556487深入理解安卓日志系统(logcat/liblog/logd)TonyBuilder2020-12-125,456阅读7分钟 一、总体介绍  安卓日志系统是开发者比较熟悉的模块,每个开发者在开发中都会是用......
  • postgresql数据库的基本使用
    登录控制台root@kali:~#sudo-upostgrespsqlpsql(10.5(Debian10.5-1))Type"help"forhelp.postgres=#设置postgres密码postgres=#\passwordpostgres创建一个新用户msf_db因为postgers用户具有很高的权限,通常我们不会直接以这个身份登录,而是会另外创建一个新......