go源码阅读:database/sql包

  • Open会返回DB对象并开启一条connectionOpener线程

    • connectionOpener主要处理下面提到的”当前连接数大于maxOpen会陷入等待”的连接资源请求
  • DB的核心方法: conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error)

    • 优先返回连接池里的连接
    • 当前连接数大于maxOpen会陷入等待, 等待取决于ctx, 也即由调用方控制
    • 其余情况则返回一个新连接
  • DB的连接池: freeConn []*driverConn

  • DB的核心方法: putConnDBLocked(conn, err) bool

    • 如果当前连接数大于maxOpen则直接返回false, 上层看到false则直接关闭该连接conn
    • 优先满足正在等待连接资源请求的(connRequests是一个map,可以看出请求连接资源并无优先级的说法)
    • 如果MaxIdleConns < len(freeConn), 即连接池满了, 则直接返回false, 上层看到false则直接关闭该连接conn
    • 否则丢到连接池freeConn中
  • 清理线程(connectionCleaner):

    • SetConnMaxLifetime,SetConnMaxIdleTime时才会去起唯一的一条清理线程
    • 清理线程定期清理连接池freeConn的连接, 根据maxLifetime和createAt清理, 也根据maxIdleTime和returnedAt清理
    • 有趣的是清理线程并不理会MaxOpen和MaxIdleConns是多少, 只关注MaxLifetime和MaxIdleTime, 反正过期了就清理
  • sql执行方法如Query,Exec,Ping等, 都会先去调conn获取连接, 再用其连接执行sql, 最后将putConnDBLocked(conn), (query是等rows全部scan完close再putConnDBLocked(conn))

  • 关于resetSession最终的去处, 总的来说就是reset了个寂寞, 最终居然只是conn.SetReadDeadline(time.Time{})?

阅读更多

go源码阅读:net/http的Transport

  • Transport是RoundTripper接口的实现: func RoundTrip(req *Request) (*Response, error)

  • Transport对外只提供方法: func RoundTrip(req *Request) (*Response, error)

  • Transport的内部对象idleLRU connLRU写得不错, 简单实现了LRU

  • http.Client就是在Tranport上简单封装一层

  • Transport就是一个连接池, 池子里面放着persistConn连接对象(idleConn map[connectMethodKey][]*persistConn)

  • queueForIdleConn: 根据请求的connectMethodKey从t.idleConn获取一个[]*persistConn切片, 并从切片中,根据算法获取一个有效的空闲连接。如果未获取到空闲连接,则将wantConn结构体放入t.idleConnWait[w.key]等待队列

  • 连接释放逻辑在 (t *Transport) tryPutIdleConn(pconn *persistConn)

    • 哪些情况才回去调 tryPutIdleConn:
      1. 大部分的异常情况
      2. responseBody read完: 代码详细见 case bodyEOF := <-waitForBodyRead
  • dialConnFor: 会调用t.dialConn获取一个真正的*persistConn。并将这个连接传递给w, 如果w已经获取到了连接,则会传递失败,此时调用t.putOrCloseIdleConn将连接放回空闲连接池。

  • dialConn:

    1. 调用t.dial(ctx, “tcp”, cm.addr())创建TCP连接并将其赋予刚new的persistConn
    2. 如果是https的请求,则对请求建立安全的tls传输通道
    3. 为persistConn创建读写buffer,如果用户没有自定义读写buffer的大小,读写bufffer的大小默认为4096
    4. 执行go pconn.readLoop()和go pconn.writeLoop()开启读写循环然后返回连接
  • dialConn里面这段代码是开启http2的核心

阅读更多

2020年的绘画之路

  • 今年年初买了正版CSP, 开始了正式的练画之路

  • 完整过了遍美术基础的视频, 从透视到色彩理论, 但感觉没啥卵用, 画画这事还是得靠堆练习量, 从小到大涂涂画画, 咱没科班基础, 但手感还有的

  • 今年涂涂画画, 没画出什么成品, 草稿一堆…糊糊涂涂一年就过去了

阅读更多