英文:
GoLang - bbolt - invalid memory address or nil pointer dereference
问题
我正在尝试使用文件数据库bbolt作为键值存储。以下是我的代码:
package handler
import (
"encoding/json"
"log"
"net/http"
"os"
"go.etcd.io/bbolt"
bolt "go.etcd.io/bbolt"
yml "gopkg.in/yaml.v3"
)
type urlDB struct {
db *bbolt.DB
}
func (u urlDB) ensureDB() {
u.db, _ = bolt.Open("url.db", 0600, nil)
}
func MapHandler(pathsToURLs map[string]string, fallback http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if _, ok := pathsToURLs[path]; ok {
http.Redirect(w, r, pathsToURLs[path], http.StatusFound)
} else {
fallback.ServeHTTP(w, r)
}
}
}
func DefaultMap(fallback http.Handler) http.HandlerFunc {
db := urlDB{}
db.ensureDB()
defer db.db.Close()
bktName := "URLBucket"
createBucket(db.db, bktName)
addSampleData(db.db, bktName, "/gm", "https://mail.google.com")
addSampleData(db.db, bktName, "/ym", "https://mail.yahoo.com")
pathToURLs := make(map[string]string)
getData(db.db, bktName, pathToURLs)
return MapHandler(pathToURLs, fallback)
}
func createBucket(db *bbolt.DB, bktName string) {
db.Update(func(tx *bbolt.Tx) error {
_, _ = tx.CreateBucketIfNotExists([]byte(bktName))
return nil
})
}
func addSampleData(db *bbolt.DB, bktName, key, value string) {
db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bktName))
_ = b.Put([]byte(key), []byte(value))
return nil
})
}
func getData(db *bbolt.DB, bktName string, pathToURLs map[string]string) {
db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bktName))
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
pathToURLs[string(k)] = string(v)
}
return nil
})
}
在main.go中调用handler:DefaultMap
的代码如下:
mux := http.NewServeMux()
var urlHandler http.HandlerFunc
urlHandler = handler.DefaultMap(mux)
http.ListenAndServe(":8080", urlHandler)
但是我得到以下错误:
panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x1b8 pc=0x6126cf]
goroutine 1 [running]:
go.etcd.io/bbolt.(*DB).Close(0x0)
panic({0x686180, 0x8dcb50})
/usr/local/go/src/runtime/panic.go:1038 +0x215
go.etcd.io/bbolt.(*DB).beginRWTx(0x0)
/home/xx/coding/go/packages/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:634 +0x38
go.etcd.io/bbolt.(*DB).Begin(0x0, 0x0)
/home/xx/coding/go/packages/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:589 +0x1d
go.etcd.io/bbolt.(*DB).Update(0x0, 0xc000187e38)
/home/xx/coding/go/packages/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:725 +0x3e
github.com/xx/urlshortner/handler.createBucket(0x6c588d, {0x6c6358, 0xc000187ec8})
/home/xx/coding/go/src/urlshortner/handler/handler.go:97 +0x48
github.com/xx/urlshortner/handler.DefaultMap({0x7243e0, 0xc00014a300})
/home/xx/coding/go/src/urlshortner/handler/handler.go:88 +0x95
main.main()
/home/xx/coding/go/src/urlshortner/main.go:24 +0xcc
exit status 2
帮助将不胜感激。
谢谢。
英文:
I am trying to use file database bbolt as a key/value storage. Below is my code
package handler
import (
"encoding/json"
"log"
"net/http"
"os"
"go.etcd.io/bbolt"
bolt "go.etcd.io/bbolt"
yml "gopkg.in/yaml.v3"
)
type urlDB struct {
db *bbolt.DB
}
func (u urlDB) ensureDB() {
u.db, _ = bolt.Open("url.db", 0600, nil)
}
func MapHandler(pathsToURLs map[string]string, fallback http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if _, ok := pathsToURLs[path]; ok {
http.Redirect(w, r, pathsToURLs[path], http.StatusFound)
} else {
fallback.ServeHTTP(w, r)
}
}
}
func DefaultMap(fallback http.Handler) http.HandlerFunc {
db := urlDB{}
db.ensureDB()
//bkt := db.db.createBucket()
//createSampleData(bkt)
defer db.db.Close()
bktName := "URLBucket"
createBucket(db.db, bktName)
addSampleData(db.db, bktName, "/gm", "https://mail.google.com")
addSampleData(db.db, bktName, "/ym", "https://mail.yahoo.com")
pathToURLs := make(map[string]string)
getData(db.db, bktName, pathToURLs)
return MapHandler(pathToURLs, fallback)
}
func createBucket(db *bbolt.DB, bktName string) {
db.Update(func(tx *bbolt.Tx) error {
_, _ = tx.CreateBucketIfNotExists([]byte(bktName))
return nil
})
}
func addSampleData(db *bbolt.DB, bktName, key, value string) {
db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bktName))
_ = b.Put([]byte(key), []byte(value))
return nil
})
}
func getData(db *bbolt.DB, bktName string, pathToURLs map[string]string) {
db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket([]byte(bktName))
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
pathToURLs[string(k)] = string(v)
}
return nil
})
}
So while calling this handler:DefaultMap
from main.go with below code
mux := http.NewServeMux()
var urlHandler http.HandlerFunc
urlHandler = handler.DefaultMap(mux)
http.ListenAndServe(":8080", urlHandler)
But I am getting error as below
panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x1b8 pc=0x6126cf]
goroutine 1 [running]:
go.etcd.io/bbolt.(*DB).Close(0x0)
panic({0x686180, 0x8dcb50})
/usr/local/go/src/runtime/panic.go:1038 +0x215
go.etcd.io/bbolt.(*DB).beginRWTx(0x0)
/home/xx/coding/go/packages/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:634 +0x38
go.etcd.io/bbolt.(*DB).Begin(0x0, 0x0)
/home/xx/coding/go/packages/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:589 +0x1d
go.etcd.io/bbolt.(*DB).Update(0x0, 0xc000187e38)
/home/xx/coding/go/packages/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:725 +0x3e
github.com/xx/urlshortner/handler.createBucket(0x6c588d, {0x6c6358, 0xc000187ec8})
/home/xx/coding/go/src/urlshortner/handler/handler.go:97 +0x48
github.com/xx/urlshortner/handler.DefaultMap({0x7243e0, 0xc00014a300})
/home/xx/coding/go/src/urlshortner/handler/handler.go:88 +0x95
main.main()
/home/xx/coding/go/src/urlshortner/main.go:24 +0xcc
exit status 2
Any help much appreciated.
Thank you.
答案1
得分: 2
这行代码:
github.com/xx/urlshortner/handler.createBucket(0x6c588d, {0x6c6358, 0xc000187ec8})
表示错误出现在 createBucket
函数中。看一下 createBucket
函数的代码:
db.Update(func(tx *bbolt.Tx) error {
根据堆栈跟踪,它调用了 Update
函数,而 db
是唯一可能为 nil 的东西。
追踪调用,你可以看到:
func (u urlDB) ensureDB() {
u.db, _ = bolt.Open("url.db", 0600, nil)
}
因此,打开数据库失败,u.db
是 nil。
英文:
This line:
github.com/xx/urlshortner/handler.createBucket(0x6c588d, {0x6c6358, 0xc000187ec8})
says error is in createBucket
. Looking at createBucket
:
db.Update(func(tx *bbolt.Tx) error {
Based on the stack trace, it calls Update
, and db
is the only thing that can be nil here.
Tracing the call back, you can see:
func (u urlDB) ensureDB() {
u.db, _ = bolt.Open("url.db", 0600, nil)
}
Thus, db open failed, and u.db
is nil.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论