timshannon / bolthold

BoltHold is an embeddable NoSQL store for Go types built on BoltDB
MIT License
643 stars 45 forks source link

Multiple calls to Delete for non-existing key result in EOF error instead of ErrNotFound #116

Closed justinfx closed 4 years ago

justinfx commented 4 years ago

While handling my deletion logic and ensuring that it is non-fatal to delete a non-existing key, I have found that deleting more than once can result in an EOF being leaked from the decoding of a nil value in the bolthold delete() call.

Here is a small reproduction:

func TestDeleteEOF(t *testing.T) {
    path := "/tmp/bolthold_delete_test.db"
    os.Remove(path)
    db, err := bh.Open(path, 0666, nil)
    if err != nil {
        t.Fatal(err)
    }
    defer db.Close()
    type Item struct{ Name string }
    if err = db.Insert("key", &Item{"Name"}); err != nil {
        t.Fatal(err)
    }
    empty := &Item{}
    for i := 1; i < 5; i++ {
        t.Logf("Delete #%d", i)
        err := db.Delete("key", empty)
        if err != nil && !errors.Is(err, bh.ErrNotFound) {
            t.Fatalf("unexpected error after delete #%d: %v", i, err)
        }
    }
}

// unexpected error after delete #2: EOF

I could catch the EOF as well as ErrNotFound, but I am not sure if an EOF could also come from a legitimate error talking to bolt.

timshannon commented 4 years ago

Yeah it's hitting the end of an iterator I think. I should capture that and treat it like a Not Found.

Thanks,

justinfx commented 4 years ago

Thanks for the fast fix!