为什么 leveldb 错误只在 10% 的测试运行中出现,如何解决这个问题?

huangapple go评论151阅读模式
英文:

Why is leveldb error appears only in 10% of test runs and how to solve it?

问题

我正在使用go版本的leveldb来存储我的数据。我编写了一些简单的辅助函数来操作数据库。同时,我为它们编写了一个测试(如下所示)。但是测试在大约10%的运行中会抛出错误(以下是堆栈跟踪)。这个错误的原因是什么,我该如何解决它?

辅助函数:

  1. package data
  2. import (
  3. "path"
  4. "runtime"
  5. "github.com/syndtr/goleveldb/leveldb"
  6. )
  7. var base = openDB()
  8. func openDB() *leveldb.DB {
  9. _, filename, _, _ := runtime.Caller(0)
  10. dbPath := path.Dir(filename) + "/leveldb"
  11. db, _ := leveldb.OpenFile(dbPath, nil)
  12. return db
  13. }
  14. // 从数据库中根据键获取值
  15. func Get(key []byte) []byte {
  16. output, getErr := base.Get(key, nil)
  17. if getErr != nil {
  18. return nil
  19. }
  20. return output
  21. }
  22. // 将键和值放入数据库(如果值存在,请使用Change()函数代替)
  23. func Put(key []byte, value []byte) {
  24. valueExists, _ := base.Has(key, nil)
  25. if valueExists {
  26. return
  27. }
  28. base.Put(key, value, nil)
  29. }
  30. // 此函数仅用于在测试后删除值,请勿在其他情况下调用它
  31. func TestRM(key []byte) {
  32. base.Delete(key, nil)
  33. }

测试:

  1. func TestPutValue(t *testing.T) {
  2. key := []byte{1, 2, 3}
  3. val := []byte{1, 2, 3, 4, 5}
  4. Put(key, val)
  5. val2 := Get(key)
  6. if !reflect.DeepEqual(val, val2) {
  7. t.Error("values are not equal")
  8. }
  9. TestRM(key)
  10. }

堆栈跟踪:

  1. --- FAIL: TestPutValue (0.00s)
  2. panic: runtime error: invalid memory address or nil pointer dereference [recovered]
  3. panic: runtime error: invalid memory address or nil pointer dereference
  4. [signal SIGSEGV: segmentation violation code=0x1 addr=0x188 pc=0x1149a7c]
  5. goroutine 6 [running]:
  6. testing.tRunner.func1.2(0x1188020, 0x12d05c0)
  7. /usr/local/go/src/testing/testing.go:1143 +0x332
  8. testing.tRunner.func1(0xc000001380)
  9. /usr/local/go/src/testing/testing.go:1146 +0x4b6
  10. panic(0x1188020, 0x12d05c0)
  11. /usr/local/go/src/runtime/panic.go:965 +0x1b9
  12. github.com/syndtr/goleveldb/leveldb.(*DB).isClosed(...)
  13. /Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db_state.go:230
  14. github.com/syndtr/goleveldb/leveldb.(*DB).ok(...)
  15. /Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db_state.go:235
  16. github.com/syndtr/goleveldb/leveldb.(*DB).Has(0x0, 0xc00001c1a8, 0x3, 0x3, 0x0, 0xc000038600, 0x0, 0x0)
  17. /Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db.go:852 +0x5c
  18. sync_tree/data.Put(0xc00001c1a8, 0x3, 0x3, 0xc00001c1ab, 0x5, 0x5)
  19. /Users/danilafominyh/Documents/sync_tree_server/data/database.go:31 +0x58
  20. sync_tree/data.TestPutValue(0xc000001380)
  21. /Users/danilafominyh/Documents/sync_tree_server/data/database_test.go:11 +0xb3
  22. testing.tRunner(0xc000001380, 0x11c4b68)
  23. /usr/local/go/src/testing/testing.go:1193 +0xef
  24. created by testing.(*T).Run
  25. /usr/local/go/src/testing/testing.go:1238 +0x2b3
  26. FAIL sync_tree/data 0.167s
  27. FAIL
  28. 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:

  1. package data
  2. import (
  3. "path"
  4. "runtime"
  5. "github.com/syndtr/goleveldb/leveldb"
  6. )
  7. var base = openDB()
  8. func openDB() *leveldb.DB {
  9. _, filename, _, _ := runtime.Caller(0)
  10. dbPath := path.Dir(filename) + "/leveldb"
  11. db, _ := leveldb.OpenFile(dbPath, nil)
  12. return db
  13. }
  14. // get value by key from database
  15. func Get(key []byte) []byte {
  16. output, getErr := base.Get(key, nil)
  17. if getErr != nil {
  18. return nil
  19. }
  20. return output
  21. }
  22. // put key by some value to database (if value exists use Change()
  23. // func instead)
  24. func Put(key []byte, value []byte) {
  25. valueExists, _ := base.Has(key, nil)
  26. if valueExists {
  27. return
  28. }
  29. base.Put(key, value, nil)
  30. }
  31. // function is made only to remove values after testing, dont call it in
  32. // any other case
  33. func TestRM(key []byte) {
  34. base.Delete(key, nil)
  35. }

Test:

  1. func TestPutValue(t *testing.T) {
  2. key := []byte{1, 2, 3}
  3. val := []byte{1, 2, 3, 4, 5}
  4. Put(key, val)
  5. val2 := Get(key)
  6. if !reflect.DeepEqual(val, val2) {
  7. t.Error("values are not equal")
  8. }
  9. TestRM(key)
  10. }

StackTrace:

  1. --- FAIL: TestPutValue (0.00s)
  2. panic: runtime error: invalid memory address or nil pointer dereference [recovered]
  3. panic: runtime error: invalid memory address or nil pointer dereference
  4. [signal SIGSEGV: segmentation violation code=0x1 addr=0x188 pc=0x1149a7c]
  5. goroutine 6 [running]:
  6. testing.tRunner.func1.2(0x1188020, 0x12d05c0)
  7. /usr/local/go/src/testing/testing.go:1143 +0x332
  8. testing.tRunner.func1(0xc000001380)
  9. /usr/local/go/src/testing/testing.go:1146 +0x4b6
  10. panic(0x1188020, 0x12d05c0)
  11. /usr/local/go/src/runtime/panic.go:965 +0x1b9
  12. github.com/syndtr/goleveldb/leveldb.(*DB).isClosed(...)
  13. /Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db_state.go:230
  14. github.com/syndtr/goleveldb/leveldb.(*DB).ok(...)
  15. /Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db_state.go:235
  16. github.com/syndtr/goleveldb/leveldb.(*DB).Has(0x0, 0xc00001c1a8, 0x3, 0x3, 0x0, 0xc000038600, 0x0, 0x0)
  17. /Users/danilafominyh/go/pkg/mod/github.com/syndtr/goleveldb@v1.0.0/leveldb/db.go:852 +0x5c
  18. sync_tree/data.Put(0xc00001c1a8, 0x3, 0x3, 0xc00001c1ab, 0x5, 0x5)
  19. /Users/danilafominyh/Documents/sync_tree_server/data/database.go:31 +0x58
  20. sync_tree/data.TestPutValue(0xc000001380)
  21. /Users/danilafominyh/Documents/sync_tree_server/data/database_test.go:11 +0xb3
  22. testing.tRunner(0xc000001380, 0x11c4b68)
  23. /usr/local/go/src/testing/testing.go:1193 +0xef
  24. created by testing.(*T).Run
  25. /usr/local/go/src/testing/testing.go:1238 +0x2b3
  26. FAIL sync_tree/data 0.167s
  27. FAIL
  28. Error: Tests failed.

答案1

得分: 1

很可能在db, _ := leveldb.OpenFile(dbPath, nil)这一行中,应用程序出现了错误,但被忽略了。要么在openDB函数中,当leveldb.OpenFile返回错误时引发panic,要么返回错误信息。

  1. func openDB() *leveldb.DB {
  2. _, filename, _, _ := runtime.Caller(0)
  3. dbPath := path.Dir(filename) + "/leveldb"
  4. db, err := leveldb.OpenFile(dbPath, nil)
  5. if err != nil {
  6. panic(fmt.Errorf("无法打开leveldb数据库:%w", err))
  7. }
  8. return db
  9. }

免责声明:这并不能解决问题,但它会给你一个线索,指出问题出在哪里。

英文:

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

  1. func openDB() *leveldb.DB {
  2. _, filename, _, _ := runtime.Caller(0)
  3. dbPath := path.Dir(filename) + "/leveldb"
  4. db, err := leveldb.OpenFile(dbPath, nil)
  5. if err != nil {
  6. panic(fmt.Errorf("could not open leveldb database: %w", err))
  7. }
  8. return db
  9. }

Disclaimer: It's not going to solve the issue, but it will give you a clue what is wrong.

huangapple
  • 本文由 发表于 2021年9月17日 01:16:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/69212620.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定