- 之前用到了gh-ost做大表改表工具, 回过来看看源码, 本篇为阅读源码的笔记
- 源码版本:
- 源码仓库: https://github.com/github/gh-ost
tls/handshake_server.go: serverHandshakeState
tls/common.go: Conn.PeerCertificates
tls/handshake_client.go: doFullHandshake:
tls/handshake_client.go: clientHandshake
tls/handshake_server.go: serverHandshake
tls.Conn: handlePostHandshakeMessage/handleKeyUpdate: KeyUpdate指的就是tls最后的那个对称密钥(变量名叫trafficSecret
)
备份逻辑就在MongoDump的Dump方法 (mongodump/mongodump.go/MongoDump.Dump)
Dump主要分4步:
后面会经常提到Intent
, 这是MongoDump自己的一个抽象概念, 可以简单理解为备份任务单元, 例如一个collection的备份对应一个Intent, oplog的备份对应一个Intent等等; 在阅读源码时你可以将Intent
在脑海里替换成Task
. 关于Intent
详见本文后面章节
核心逻辑见以下源码及注释(为了方便阅读, 这里我删减了些不关键的逻辑):
pSync
接收来自源Redis的数据再回放到目标Redisdatabase/sql
最主要还是实现了连接池逻辑Open会返回DB对象并开启一条connectionOpener线程
DB的核心方法: conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error)
DB的连接池: freeConn []*driverConn
DB的核心方法: putConnDBLocked(conn, err) bool
清理线程(connectionCleaner):
sql执行方法如Query,Exec,Ping等, 都会先去调conn获取连接, 再用其连接执行sql, 最后将putConnDBLocked(conn), (query是等rows全部scan完close再putConnDBLocked(conn))
关于resetSession最终的去处, 总的来说就是reset了个寂寞, 最终居然只是conn.SetReadDeadline(time.Time{})
?
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)
dialConnFor: 会调用t.dialConn获取一个真正的*persistConn。并将这个连接传递给w, 如果w已经获取到了连接,则会传递失败,此时调用t.putOrCloseIdleConn将连接放回空闲连接池。
dialConn:
dialConn里面这段代码是开启http2的核心
cmd/go/internal/modcmd
cmd/go/internal/modfetch
cmd/go/internal/modget
cmd/go/internal/modload