gopeed icon indicating copy to clipboard operation
gopeed copied to clipboard

报错【bolt.Close(): funlock error: The segment is already unlocked】

Open MrGlp opened this issue 1 year ago • 7 comments

报错【bolt.Close(): funlock error: The segment is already unlocked】

  1. 代码中有一个 init 方法,每次服务直接终止,那么未完成的下载任务状态会变成 pause 我会在 init 方法中调用 continueAll() 方法重新唤起未完成的任务,保障服务挂掉任务不丢失,随后就会报日志的错误 企业微信截图_16890736252938

本次测试我启动了俩下载任务,就是左侧导航栏的两个文件夹,每次重启都会报这个错,有时候服务就会阻塞住

但是也有可能恢复服务启动成功 企业微信截图_16890736429174

这个大概是什么原因,只知道锁已经释放,但是目前没分析出来出错的具体原因

MrGlp avatar Jul 11 '23 11:07 MrGlp

init 方法是我代码中的,服务启动时候我期待重新唤起 上次异常终止的任务就这样写了

MrGlp avatar Jul 11 '23 11:07 MrGlp

可以给个能复现的代码吗,另外错误是在哪个地方触发打印的?

monkeyWie avatar Jul 11 '23 11:07 monkeyWie

核心代码在这块,这个是我一个web服务下面的 init 方法,加上这行代码就报错【Downloader.ContinueAll() // TODO:初始化锁释放问题】

项目启动时候会先卡在红圈这里 image 卡大概几十秒然后下面正常执行 本地如果我有两个下载任务进行中,然后我直接停止服务,然后重新启动服务,初始化调用 ContinueAll() 方法就会报这错

报错日志是bbolt里面的日志 企业微信截图_1689134365711

package downloader

import ( "fmt" "github.com/GopeedLab/gopeed/pkg/base" "github.com/GopeedLab/gopeed/pkg/download" "github.com/GopeedLab/gopeed/pkg/protocol/http" "runtime/debug" )

// Downloader 初始化全局下载器 var Downloader *download.Downloader

// 初始化下载器 // 初始化离线下载文件存储路径 StorageDir func init() { defer func() { if r := recover(); r != nil { fmt.Printf("Recovered from panic: %v\n", r) debug.PrintStack() } }() downloadStoreCfg := &download.DownloaderStoreConfig{ FirstLoad: true, // 读取新配置 MaxRunning: 2000, DownloadDir: "./library/download/base/", // 默认存储目录 ProtocolConfig: map[string]any{ "http": map[string]any{ "connections": 8, }, "bt": map[string]any{ "trackerSubscribeUrls": []string{ "https://cf.trackerslist.com/best.txt", }, "trackers": []string{ "udp://tracker.coppersurfer.tk:6969/announce", "udp://tracker.leechers-paradise.org:6969/announce", "udp://tracker.altrosky.nl:6969/announce", "udp://opentracker.i2p.rocks:6969/announce", }, }, }, //特殊协议支持 Extra: map[string]any{}, //额外配置信息 } downloadCfg := &download.DownloaderConfig{ Storage: download.NewBoltStorage("./library/download/bolt/"), // bolt 存储, 事务保证 DownloaderStoreConfig: downloadStoreCfg, } downloadCfg.Init() Downloader = download.NewDownloader(downloadCfg) Downloader.Listener(func(event *download.Event) { // ticker := time.NewTicker(10 * time.Second) // defer ticker.Stop() //OuterLoop: // for { // select { // case <-ticker.C: taskId := event.Task.ID

	speedInMB := float64(event.Task.Progress.Speed) / (1024 * 1024)
	fmt.Printf("taskId: %s speed: %.2f MB/s\n", taskId, speedInMB)

	progressPercentage := float64(event.Task.Progress.Downloaded) / float64(event.Task.Size) * 100
	fmt.Printf("taskId: %s transferred: %.2f%%\n", taskId, progressPercentage)

	switch event.Key {
	case download.EventKeyDone:

	case download.EventKeyFinally: // 调用 s3 上传 api
		fmt.Println("task 下载完成, taskId: ", taskId)
		break
	default:

	}
})

if err := Downloader.Setup(); err != nil {
	panic(err)
}
Downloader.PutConfig(downloadStoreCfg)
fmt.Println("Downloader init ok!")

// 每次重启下载服务后, 需要激活受影响的服务
Downloader.ContinueAll() // TODO:初始化锁释放问题

}

/* type ReqExtra struct { Method string json:"method" Header map[string]string json:"header" Body string json:"body" }

type OptsExtra struct {
	Connections int `json:"connections"`
}

*/ func main() { resolveRes, err := Downloader.Resolve(&base.Request{ URL: "https://www.baidu.com/index.htmlss", }) if err != nil { fmt.Println("resolver err") panic(err) } fmt.Println("resolve_id", resolveRes.ID)

id, err := Downloader.Create(resolveRes.ID, &base.Options{
	Name: "testIndex.html",
	Path: "./download/gopeed/file2",
	Extra: http.OptsExtra{
		Connections: 8,
	},
})
if err != nil {
	panic(err)
}
fmt.Println("third_task_id", id)

}

MrGlp avatar Jul 12 '23 06:07 MrGlp

Downloader.ContinueAll() // TODO:初始化锁释放问题

是这行代码导致的,他好像唤起了服务异常终止导致暂停的两个任务,然后两个任务开始恢复下载阶段报错

MrGlp avatar Jul 12 '23 06:07 MrGlp

我这个就是一个 web 服务,上面那一大段是初始化下载器配置的 init 代码,最后那一行目的是想每次服务如果异常终止,重新启动服务的时候恢复下载的任务

但是加上目前确实会恢复,但是也会有那行报错

下载任务的接口代码感觉不用贴,那个没啥 最后的代码内容就这样,创建个下载任务就返回了 taskId, err = downloader.Downloader.Create(resolveRes.ID, options) if err != nil { panic(err) }

return

MrGlp avatar Jul 12 '23 06:07 MrGlp

打个断点在错误日志输出的地方,看看堆栈是哪里触发的,而且看起来是文件句柄被占用导致无法关闭,你排查下是不是哪里还有占用数据库文件没有释放: image

monkeyWie avatar Jul 12 '23 07:07 monkeyWie

image

确实是我服务初始化的时候调用这个 continue 方法导致的报错,有两个任务,第二个任务调用 continue 就出错了

image

另外还有就是我这边生成了两个db,这种情况是不是不该出现,初始化的时候有问题了 image

MrGlp avatar Jul 12 '23 08:07 MrGlp

拉下最新的代码试试

monkeyWie avatar Jul 13 '23 05:07 monkeyWie

拉取最新代码后这个问题解决了

请问下大概是啥原因,多任务锁释放问题么 另外我这边同时存在 .torrent.bolt.db 和 gopeed.db 俩文件应该是正常的吧,第一个是默认的位置不支持修改,功能不一样

MrGlp avatar Jul 13 '23 06:07 MrGlp

之前bt任务初始化的地方有并发问题,刚好修复掉了,两个db是正常的

monkeyWie avatar Jul 13 '23 06:07 monkeyWie

多谢

MrGlp avatar Jul 13 '23 06:07 MrGlp