英文:
Why is leveldb error appears only in 10% of test runs and how to solve it?
问题
我正在使用go版本的leveldb来存储我的数据。我编写了一些简单的辅助函数来操作数据库。同时,我为它们编写了一个测试(如下所示)。但是测试在大约10%的运行中会抛出错误(以下是堆栈跟踪)。这个错误的原因是什么,我该如何解决它?
辅助函数:
package data
import (
"path"
"runtime"
"github.com/syndtr/goleveldb/leveldb"
)
var base = openDB()
func openDB() *leveldb.DB {
_, filename, _, _ := runtime.Caller(0)
dbPath := path.Dir(filename) + "/leveldb"
db, _ := leveldb.OpenFile(dbPath, nil)
return db
}
// 从数据库中根据键获取值
func Get(key []byte) []byte {
output, getErr := base.Get(key, nil)
if getErr != nil {
return nil
}
return output
}
// 将键和值放入数据库(如果值存在,请使用Change()函数代替)
func Put(key []byte, value []byte) {
valueExists, _ := base.Has(key, nil)
if valueExists {
return
}
base.Put(key, value, nil)
}
// 此函数仅用于在测试后删除值,请勿在其他情况下调用它
func TestRM(key []byte) {
base.Delete(key, nil)
}
测试:
func TestPutValue(t *testing.T) {
key := []byte{1, 2, 3}
val := []byte{1, 2, 3, 4, 5}
Put(key, val)
val2 := Get(key)
if !reflect.DeepEqual(val, val2) {
t.Error("values are not equal")
}
TestRM(key)
}
堆栈跟踪:
--- FAIL: TestPutValue (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x188 pc=0x1149a7c]
goroutine 6 [running]:
testing.tRunner.func1.2(0x1188020, 0x12d05c0)
/usr/local/go/src/testing/testing.go:1143 +0x332
testing.tRunner.func1(0xc000001380)
/usr/local/go/src/testing/testing.go:1146 +0x4b6
panic(0x1188020, 0x12d05c0)
/usr/local/go/src/runtime/panic.go:965 +0x1b9
github.com/syndtr/goleveldb/leveldb.(*DB).isClosed(...)
/Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db_state.go:230
github.com/syndtr/goleveldb/leveldb.(*DB).ok(...)
/Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db_state.go:235
github.com/syndtr/goleveldb/leveldb.(*DB).Has(0x0, 0xc00001c1a8, 0x3, 0x3, 0x0, 0xc000038600, 0x0, 0x0)
/Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db.go:852 +0x5c
sync_tree/data.Put(0xc00001c1a8, 0x3, 0x3, 0xc00001c1ab, 0x5, 0x5)
/Users/danilafominyh/Documents/sync_tree_server/data/database.go:31 +0x58
sync_tree/data.TestPutValue(0xc000001380)
/Users/danilafominyh/Documents/sync_tree_server/data/database_test.go:11 +0xb3
testing.tRunner(0xc000001380, 0x11c4b68)
/usr/local/go/src/testing/testing.go:1193 +0xef
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:1238 +0x2b3
FAIL sync_tree/data 0.167s
FAIL
Error: Tests failed.
英文:
I am using go version of leveldb to store my data. I made some simple helper functions to manipulate the database. Also I wrote a test for them (below). But the test is throwing error in around 10% runs (stack trace below). What is the reason of that error, and how can I solve it?
Helpers:
package data
import (
"path"
"runtime"
"github.com/syndtr/goleveldb/leveldb"
)
var base = openDB()
func openDB() *leveldb.DB {
_, filename, _, _ := runtime.Caller(0)
dbPath := path.Dir(filename) + "/leveldb"
db, _ := leveldb.OpenFile(dbPath, nil)
return db
}
// get value by key from database
func Get(key []byte) []byte {
output, getErr := base.Get(key, nil)
if getErr != nil {
return nil
}
return output
}
// put key by some value to database (if value exists use Change()
// func instead)
func Put(key []byte, value []byte) {
valueExists, _ := base.Has(key, nil)
if valueExists {
return
}
base.Put(key, value, nil)
}
// function is made only to remove values after testing, dont call it in
// any other case
func TestRM(key []byte) {
base.Delete(key, nil)
}
Test:
func TestPutValue(t *testing.T) {
key := []byte{1, 2, 3}
val := []byte{1, 2, 3, 4, 5}
Put(key, val)
val2 := Get(key)
if !reflect.DeepEqual(val, val2) {
t.Error("values are not equal")
}
TestRM(key)
}
StackTrace:
--- FAIL: TestPutValue (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x188 pc=0x1149a7c]
goroutine 6 [running]:
testing.tRunner.func1.2(0x1188020, 0x12d05c0)
/usr/local/go/src/testing/testing.go:1143 +0x332
testing.tRunner.func1(0xc000001380)
/usr/local/go/src/testing/testing.go:1146 +0x4b6
panic(0x1188020, 0x12d05c0)
/usr/local/go/src/runtime/panic.go:965 +0x1b9
github.com/syndtr/goleveldb/leveldb.(*DB).isClosed(...)
/Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db_state.go:230
github.com/syndtr/goleveldb/leveldb.(*DB).ok(...)
/Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db_state.go:235
github.com/syndtr/goleveldb/leveldb.(*DB).Has(0x0, 0xc00001c1a8, 0x3, 0x3, 0x0, 0xc000038600, 0x0, 0x0)
/Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db.go:852 +0x5c
sync_tree/data.Put(0xc00001c1a8, 0x3, 0x3, 0xc00001c1ab, 0x5, 0x5)
/Users/danilafominyh/Documents/sync_tree_server/data/database.go:31 +0x58
sync_tree/data.TestPutValue(0xc000001380)
/Users/danilafominyh/Documents/sync_tree_server/data/database_test.go:11 +0xb3
testing.tRunner(0xc000001380, 0x11c4b68)
/usr/local/go/src/testing/testing.go:1193 +0xef
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:1238 +0x2b3
FAIL sync_tree/data 0.167s
FAIL
Error: Tests failed.
答案1
得分: 1
很可能在db, _ := leveldb.OpenFile(dbPath, nil)
这一行中,应用程序出现了错误,但被忽略了。要么在openDB
函数中,当leveldb.OpenFile
返回错误时引发panic,要么返回错误信息。
func openDB() *leveldb.DB {
_, filename, _, _ := runtime.Caller(0)
dbPath := path.Dir(filename) + "/leveldb"
db, err := leveldb.OpenFile(dbPath, nil)
if err != nil {
panic(fmt.Errorf("无法打开leveldb数据库:%w", err))
}
return db
}
免责声明:这并不能解决问题,但它会给你一个线索,指出问题出在哪里。
英文:
Most likely the app gets an error in db, _ := leveldb.OpenFile(dbPath, nil)
line which is ignored. Make openDB
either panic when leveldb.OpenFile
returns an error or return an error
func openDB() *leveldb.DB {
_, filename, _, _ := runtime.Caller(0)
dbPath := path.Dir(filename) + "/leveldb"
db, err := leveldb.OpenFile(dbPath, nil)
if err != nil {
panic(fmt.Errorf("could not open leveldb database: %w", err))
}
return db
}
Disclaimer: It's not going to solve the issue, but it will give you a clue what is wrong.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论