gopeed
gopeed copied to clipboard
报错【bolt.Close(): funlock error: The segment is already unlocked】
报错【bolt.Close(): funlock error: The segment is already unlocked】
- 代码中有一个 init 方法,每次服务直接终止,那么未完成的下载任务状态会变成 pause
我会在 init 方法中调用 continueAll() 方法重新唤起未完成的任务,保障服务挂掉任务不丢失,随后就会报日志的错误
本次测试我启动了俩下载任务,就是左侧导航栏的两个文件夹,每次重启都会报这个错,有时候服务就会阻塞住
但是也有可能恢复服务启动成功
这个大概是什么原因,只知道锁已经释放,但是目前没分析出来出错的具体原因
init 方法是我代码中的,服务启动时候我期待重新唤起 上次异常终止的任务就这样写了
可以给个能复现的代码吗,另外错误是在哪个地方触发打印的?
核心代码在这块,这个是我一个web服务下面的 init 方法,加上这行代码就报错【Downloader.ContinueAll() // TODO:初始化锁释放问题】
项目启动时候会先卡在红圈这里
卡大概几十秒然后下面正常执行
本地如果我有两个下载任务进行中,然后我直接停止服务,然后重新启动服务,初始化调用 ContinueAll() 方法就会报这错
报错日志是bbolt里面的日志
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)
}
Downloader.ContinueAll() // TODO:初始化锁释放问题
是这行代码导致的,他好像唤起了服务异常终止导致暂停的两个任务,然后两个任务开始恢复下载阶段报错
我这个就是一个 web 服务,上面那一大段是初始化下载器配置的 init 代码,最后那一行目的是想每次服务如果异常终止,重新启动服务的时候恢复下载的任务
但是加上目前确实会恢复,但是也会有那行报错
下载任务的接口代码感觉不用贴,那个没啥 最后的代码内容就这样,创建个下载任务就返回了 taskId, err = downloader.Downloader.Create(resolveRes.ID, options) if err != nil { panic(err) }
return
打个断点在错误日志输出的地方,看看堆栈是哪里触发的,而且看起来是文件句柄被占用导致无法关闭,你排查下是不是哪里还有占用数据库文件没有释放:
确实是我服务初始化的时候调用这个 continue 方法导致的报错,有两个任务,第二个任务调用 continue 就出错了
另外还有就是我这边生成了两个db,这种情况是不是不该出现,初始化的时候有问题了
拉下最新的代码试试
拉取最新代码后这个问题解决了
请问下大概是啥原因,多任务锁释放问题么 另外我这边同时存在 .torrent.bolt.db 和 gopeed.db 俩文件应该是正常的吧,第一个是默认的位置不支持修改,功能不一样
之前bt任务初始化的地方有并发问题,刚好修复掉了,两个db是正常的
多谢