/syncthing

源码阅读,版本1.13

Primary LanguageGoMozilla Public License 2.0MPL-2.0

syncthing

  • 调试将
if innerProcess || options.noRestart {
    syncthingMain(options)
} else {
    monitorMain(options)
}
替换成
syncthingMain(options)
  • 显示debug日志,在idea下environment设置STTRACE=model,然后debug go build github.com/syncthing/syncthing/cmd/syncthing

  • 拉取过程中会产生.xxx.tmp的中间文件

依赖列表

  • 关于Erlang语言中的supervisor trees,参照http://diaocow.iteye.com/blog/1762895
  • 文件系统通知库,github.com/syncthing/notify
  • go项目的leveldb库,github.com/syndtr/goleveldb
  • 从一个字符串中查找给定字符串,github.com/chmduquesne/rollinghash

连接步骤

  • 添加deviceID
  • 计算要连接设备的IP和port
    • 1、静态绑定IP、port
    • 2、使用本地local discovery,因为syncthing会广播自己的信息,如果发现到这个deviceID,则就能找到IP和port
    • 3、使用global discovery
  • 建立tcp连接,执行tls握手,需要执行一些验证操作

关于BEP协议, 详细的messageType交互

  • 核心连接监听代码:
①model.go
func (m *model) AddConnection
↓
②conn.Start() = (rawConnection.Start)
↓
③调用收发消息核心
func (c *rawConnection) Start() {
	go func() {
		err := c.readerLoop()
		c.internalClose(err)
	}()
	go c.writerLoop()
	go c.pingSender()
	go c.pingReceiver()
}
↓
④下面就是writerLoop、readerLoop按照事件去处理
  • supervisor服务启动,folder实现suture的service接口。服务启动时就会调用各个实现Serve()方法
① folder.go
case <-f.pullScheduled:
    pullFailTimer.Stop()
    select {
    case <-pullFailTimer.C:
    default:
    }
    pull()
↓

文件夹三种同步方式:

  • 默认:sendreceive
  • sendonly
  • recvonly
①folder.go //监控文件夹,通过文件系统和定时任务实现
if f.FSWatcherEnabled && f.CheckHealth() == nil {
    f.startWatch()
}
↓
②filesystem.go //实现了Watch方法的 basicfs_watch.go
eventChan, err := f.Filesystem().Watch(".", f.ignores, ctx, f.IgnorePerms)
↓
③basicfs_watch.go
func (f *BasicFilesystem) Watch(name string, ignore Matcher, ctx context.Context, ignorePerms bool) (<-chan Event, error) {

case outChan <- Event{Name: relPath, Type: evType}://发送文件Chan

事件订阅:

文件大小:

  • 可以通过以下命令查看文件字节大小
ls -l -k
  • wiki上有个区段表,如果目标文件大小在0 - 250 MiB,则每个区块的最大传输为128 KiB
例如:196426字节的文件,按每块128KiB切分,第一块也就是128*1024(131072),第二块用总数-第一块(65354)

goroutine核心拉取逻辑:

  • 逻辑都在folder_sendrecv.go里
pull() -> pullerIteration() -> processNeeded() -> handleFile() 塞入 copyChan
                  goroutine -> copierRoutine                    -> 触发 copierRoutine, 塞入pullChan
                  goroutine -> pullerRoutine                            -> 触发 pullerRoutine,塞入finisherChan
                  goroutine -> finisherRoutine                                 -> 触发 finisherRoutine