Lost power killed db v3.2103.0

Power loss killed two badger databases running in separate applications.
Testing with Ctrl-C also killed one.
Then downgraded to v3.2011.1 and the one destroyed with Ctrl-C became functional.
Can’t include traceback.
“New users limited to 2 links”

What version of Go are you using (go version)?

$ go version
go version go1.16.4 windows/amd64

What operating system are you using?

Windows 10

What version of Badger are you using?

v3.2103.0

Does this issue reproduce with the latest master?

Steps to Reproduce the issue

Power loss or repeatedly kill the application.

What Badger options were set?

opts := badger.DefaultOptions(path)
db1, err := badger.OpenManaged(opts)

What did you do?

Downgraded to v3.2011.1

What did you expect to see?

What did you see instead?

panic: runtime error: index out of range [3] with length 0 [recovered]
panic:
== Recovering from initIndex crash ==
File Info: [ID: 1808, Size: 19952177, Zeros: 483889]
isEnrypted: false checksumLen: 0 checksum: indexLen: 0 index:
== Recovered ==

panic: runtime error: index out of range [3] with length 0 [recovered]
panic:
== Recovering from initIndex crash ==
File Info: [ID: 1808, Size: 19952177, Zeros: 483889]
isEnrypted: false checksumLen: 0 checksum: indexLen: 0 index:
== Recovered ==

Do you capture interupts in your application? Reference this article for how to do it in your application: Graceful shutdown of Golang servers using Context and OS signals | by Pinku Deb Nath | Medium

I have that set up so I can properly close the Badger DB. At the very least add this after you create your DB connection:

	defer func() {
		err := db.Close()
		if err != nil {
			log.Fatal(err)
		}
	}()

That will allow Badger to do any best effort cleanup to avoid issues with Ctrl+C or a container being terminated externally. Nothing will help a true power outage that doesn’t provide the time to call the close function.

Specifically, if you want to gracefully handle shutdown for Ctrl+C and OS shutdown, you’ll need the the following:

interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)

go func() {
	err := server.ListenAndServe()

	if err != nil {
		log.Printf("Error running service: %s", err)
	}
}()

killSignal := <-interrupt
switch killSignal {
case os.Interrupt:
	log.Print("Received OS Interrupt")
case syscall.SIGTERM:
	log.Print("Received Termination Signal")
}

if err = server.Shutdown(context.Background()); err != nil {
	log.Printf("Shutdown error: %s", err)
}
1 Like