diff --git a/consul/mdb_table.go b/consul/mdb_table.go index 0012f5e02e..601f62f194 100644 --- a/consul/mdb_table.go +++ b/consul/mdb_table.go @@ -406,7 +406,7 @@ func (t *MDBTable) deleteWithIndex(tx *MDBTxn, idx *MDBIndex, key []byte) (num i defer func() { if r := recover(); r != nil { num = 0 - err = err + err = fmt.Errorf("Panic while deleting: %v", r) } }() @@ -543,8 +543,15 @@ func (i *MDBIndex) iterate(tx *MDBTxn, prefix []byte, first = false key, encRowId, err = cursor.Get(prefix, mdb.SET_RANGE) } else if shouldDelete { - key, encRowId, err = cursor.Get(nil, 0) + key, encRowId, err = cursor.Get(nil, mdb.GET_CURRENT) shouldDelete = false + + // LMDB will return EINVAL(22) for the GET_CURRENT op if + // there is no further keys. We treat this as no more + // keys being found. + if num, ok := err.(mdb.Errno); ok && num == 22 { + err = mdb.NotFound + } } else if i.Unique { key, encRowId, err = cursor.Get(nil, mdb.NEXT) } else { diff --git a/consul/mdb_table_test.go b/consul/mdb_table_test.go index 2ce6ca7912..13bfff5b19 100644 --- a/consul/mdb_table_test.go +++ b/consul/mdb_table_test.go @@ -703,3 +703,81 @@ func TestMDBTableIndex(t *testing.T) { t.Fatalf("bad last idx: %d", idx) } } + +func TestMDBTableDelete_Prefix(t *testing.T) { + dir, env := testMDBEnv(t) + defer os.RemoveAll(dir) + defer env.Close() + + table := &MDBTable{ + Env: env, + Name: "test", + Indexes: map[string]*MDBIndex{ + "id": &MDBIndex{ + Unique: true, + Fields: []string{"First", "Last"}, + }, + }, + Encoder: MockEncoder, + Decoder: MockDecoder, + } + if err := table.Init(); err != nil { + t.Fatalf("err: %v", err) + } + + objs := []*MockData{ + &MockData{ + Key: "1", + First: "James", + Last: "Smith", + Country: "USA", + }, + &MockData{ + Key: "1", + First: "Kevin", + Last: "Smith", + Country: "USA", + }, + &MockData{ + Key: "2", + First: "Kevin", + Last: "Wang", + Country: "USA", + }, + &MockData{ + Key: "3", + First: "Kevin", + Last: "Torres", + Country: "Mexico", + }, + &MockData{ + Key: "1", + First: "Lana", + Last: "Smith", + Country: "USA", + }, + } + + // Insert some mock objects + for _, obj := range objs { + if err := table.Insert(obj); err != nil { + t.Fatalf("err: %v", err) + } + } + + // This should nuke all kevins + num, err := table.Delete("id", "Kevin") + if err != nil { + t.Fatalf("err: %v", err) + } + if num != 3 { + t.Fatalf("expect 3 delete: %#v", num) + } + _, res, err := table.Get("id") + if err != nil { + t.Fatalf("err: %v", err) + } + if len(res) != 2 { + t.Fatalf("expect 2 result: %#v", res) + } +}