GoLang – bbolt – 无效的内存地址或空指针解引用

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

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.

huangapple
  • 本文由 发表于 2022年4月6日 01:26:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/71755988.html
匿名

发表评论

匿名网友

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

确定