Index pattern not always honored

When creating an index with CreateIndex, a pattern is used to specify
the matching keys that should be stored in the index. It is therefore
unexpected that items that do not match the pattern will be presented to
the less function that is also supplied on CreateIndex.  This change
corrects that problem by applying the pattern in two paths previously
not considered:

1. When an item is replaced in the database.
2. When an item is deleted from the database.
This commit is contained in:
Mike Haller 2021-06-15 17:26:56 -06:00
parent ae2bcacb06
commit 97feb53ded
2 changed files with 68 additions and 6 deletions

View File

@ -454,16 +454,22 @@ func (db *DB) SetConfig(config Config) error {
// will be replaced with the new one, and return the previous item. // will be replaced with the new one, and return the previous item.
func (db *DB) insertIntoDatabase(item *dbItem) *dbItem { func (db *DB) insertIntoDatabase(item *dbItem) *dbItem {
var pdbi *dbItem var pdbi *dbItem
idxs := []*index{}
for _, idx := range db.idxs {
if idx.match(item.key) {
idxs = append(idxs, idx)
}
}
prev := db.keys.Set(item) prev := db.keys.Set(item)
if prev != nil { if prev != nil {
// A previous item was removed from the keys tree. Let's // A previous item was removed from the keys tree. Let's
// fully delete this item from all indexes. // fully delete this item from all indexes.
pdbi = prev.(*dbItem) pdbi = prev.(*dbItem)
if pdbi.opts != nil && pdbi.opts.ex { if pdbi.opts != nil && pdbi.opts.ex {
// Remove it from the exipres tree. // Remove it from the expires tree.
db.exps.Delete(pdbi) db.exps.Delete(pdbi)
} }
for _, idx := range db.idxs { for _, idx := range idxs {
if idx.btr != nil { if idx.btr != nil {
// Remove it from the btree index. // Remove it from the btree index.
idx.btr.Delete(pdbi) idx.btr.Delete(pdbi)
@ -479,10 +485,7 @@ func (db *DB) insertIntoDatabase(item *dbItem) *dbItem {
// expires tree // expires tree
db.exps.Set(item) db.exps.Set(item)
} }
for _, idx := range db.idxs { for _, idx := range idxs {
if !idx.match(item.key) {
continue
}
if idx.btr != nil { if idx.btr != nil {
// Add new item to btree index. // Add new item to btree index.
idx.btr.Set(item) idx.btr.Set(item)
@ -512,6 +515,9 @@ func (db *DB) deleteFromDatabase(item *dbItem) *dbItem {
db.exps.Delete(pdbi) db.exps.Delete(pdbi)
} }
for _, idx := range db.idxs { for _, idx := range db.idxs {
if !idx.match(pdbi.key) {
continue
}
if idx.btr != nil { if idx.btr != nil {
// Remove it from the btree index. // Remove it from the btree index.
idx.btr.Delete(pdbi) idx.btr.Delete(pdbi)

View File

@ -1487,6 +1487,62 @@ func TestInsertsAndDeleted(t *testing.T) {
} }
} }
func TestInsertDoesNotMisuseIndex(t *testing.T) {
db := testOpen(t)
defer testClose(db)
fail := func(a, b string) bool { t.Fatal("Misused index"); return false }
if err := db.CreateIndex("some", "a*", fail); err != nil {
// Only one item is eligible for the index, so no comparison is necessary.
t.Fatal(err)
}
if err := db.Update(func(tx *Tx) error {
if _, _, err := tx.Set("a", "1", nil); err != nil {
return err
}
if _, _, err := tx.Set("b", "1", nil); err != nil {
return err
}
return nil
}); err != nil {
t.Fatal(err)
}
if err := db.Update(func(tx *Tx) error {
_, _, err := tx.Set("b", "2", nil)
return err
}); err != nil {
t.Fatal(err)
}
}
func TestDeleteDoesNotMisuseIndex(t *testing.T) {
db := testOpen(t)
defer testClose(db)
fail := func(a, b string) bool { t.Fatal("Misused index"); return false }
if err := db.CreateIndex("some", "a*", fail); err != nil {
// Only one item is eligible for the index, so no comparison is necessary.
t.Fatal(err)
}
if err := db.Update(func(tx *Tx) error {
if _, _, err := tx.Set("a", "1", nil); err != nil {
return err
}
if _, _, err := tx.Set("b", "1", nil); err != nil {
return err
}
return nil
}); err != nil {
t.Fatal(err)
}
if err := db.Update(func(tx *Tx) error {
_, err := tx.Delete("b")
return err
}); err != nil {
t.Fatal(err)
}
}
// test index compare functions // test index compare functions
func TestIndexCompare(t *testing.T) { func TestIndexCompare(t *testing.T) {
if !IndexFloat("1.5", "1.6") { if !IndexFloat("1.5", "1.6") {