Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
MrGlp opened this issue Jul 11, 2023 · 11 comments
Closed

Comments

@MrGlp
Copy link
Contributor

MrGlp commented Jul 11, 2023

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

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

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

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

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

@MrGlp
Copy link
Contributor Author

MrGlp commented Jul 11, 2023

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

@monkeyWie
Copy link
Member

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

@MrGlp
Copy link
Contributor Author

MrGlp commented Jul 12, 2023

核心代码在这块,这个是我一个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
Copy link
Contributor Author

MrGlp commented Jul 12, 2023

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

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

@MrGlp
Copy link
Contributor Author

MrGlp commented Jul 12, 2023

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

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

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

return

@monkeyWie
Copy link
Member

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

@MrGlp
Copy link
Contributor Author

MrGlp commented Jul 12, 2023

image

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

image

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

@monkeyWie
Copy link
Member

拉下最新的代码试试

@MrGlp
Copy link
Contributor Author

MrGlp commented Jul 13, 2023

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

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

@monkeyWie
Copy link
Member

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

@MrGlp
Copy link
Contributor Author

MrGlp commented Jul 13, 2023

多谢

@MrGlp MrGlp closed this as completed Jul 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants