From dc3a88052c71d25626a166dc1bdb8057b73c179b Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 28 Jun 2019 16:26:33 -0700 Subject: [PATCH 1/2] datastore: actually enable prefix searching, and test for it --- datastore.go | 4 ++-- datastore_test.go | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/datastore.go b/datastore.go index 53a74ab..4e61fd9 100644 --- a/datastore.go +++ b/datastore.go @@ -88,7 +88,7 @@ func (d *Datastore) GetSize(key datastore.Key) (int, error) { // Query performs a complex search query on the underlying datastore // For more information see : // https://github.com/ipfs/go-datastore/blob/aa9190c18f1576be98e974359fd08c64ca0b5a94/examples/fs.go#L96 -// https://github.com/boltdb/bolt/issues/518#issuecomment-187211346 +// https://github.com/etcd-io/bbolt#prefix-scans func (d *Datastore) Query(q query.Query) (query.Results, error) { resBuilder := query.NewResultBuilder(q) if err := d.db.View(func(tx *bbolt.Tx) error { @@ -110,7 +110,7 @@ func (d *Datastore) Query(q query.Query) (query.Results, error) { return nil } pref := []byte(q.Prefix) - for k, _ := cursor.Seek(pref); bytes.HasPrefix(k, pref); k, _ = cursor.Next() { + for k, _ := cursor.Seek(pref); k != nil && bytes.HasPrefix(k, pref); k, _ = cursor.Next() { result := query.Result{} key := datastore.NewKey(string(k)) result.Entry.Key = key.String() diff --git a/datastore_test.go b/datastore_test.go index 7d5d7c0..77df4e9 100644 --- a/datastore_test.go +++ b/datastore_test.go @@ -1,7 +1,6 @@ package dsbbolt import ( - "fmt" "testing" "reflect" @@ -71,8 +70,8 @@ func Test_Datastore(t *testing.T) { if err != nil { t.Fatal(err) } - for _, v := range res { - fmt.Printf("%+v\n", v) + if len(res) == 0 { + t.Fatal("bad number of results") } // test a query where we dont specify a search key rs, err = ds.Query(query.Query{}) @@ -83,8 +82,20 @@ func Test_Datastore(t *testing.T) { if err != nil { t.Fatal(err) } - for _, v := range res { - fmt.Printf("%+v\n", v) + if len(res) == 0 { + t.Fatal("bad number of results") + } + // test a query where we specify a partial prefix + rs, err = ds.Query(query.Query{Prefix: "/kek"}) + if err != nil { + t.Fatal(err) + } + res, err = rs.Rest() + if err != nil { + t.Fatal(err) + } + if len(res) == 0 { + t.Fatal("bad number of results") } if err := ds.Delete(key); err != nil { t.Fatal(err) From 134ec588411cfe404e7418330576f6d61e03de79 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 28 Jun 2019 16:41:09 -0700 Subject: [PATCH 2/2] datastore: optimize non-keysOnly searches to avoid extra datastore calls --- datastore.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/datastore.go b/datastore.go index 4e61fd9..2a90160 100644 --- a/datastore.go +++ b/datastore.go @@ -94,12 +94,12 @@ func (d *Datastore) Query(q query.Query) (query.Results, error) { if err := d.db.View(func(tx *bbolt.Tx) error { cursor := tx.Bucket(d.bucket).Cursor() if q.Prefix == "" { - for k, _ := cursor.First(); k != nil; k, _ = cursor.Next() { + for k, v := cursor.First(); k != nil; k, v = cursor.Next() { result := query.Result{} key := datastore.NewKey(string(k)) result.Entry.Key = key.String() if !q.KeysOnly { - result.Entry.Value, result.Error = d.Get(key) + result.Entry.Value = v } select { case resBuilder.Output <- result: @@ -110,12 +110,12 @@ func (d *Datastore) Query(q query.Query) (query.Results, error) { return nil } pref := []byte(q.Prefix) - for k, _ := cursor.Seek(pref); k != nil && bytes.HasPrefix(k, pref); k, _ = cursor.Next() { + for k, v := cursor.Seek(pref); k != nil && bytes.HasPrefix(k, pref); k, v = cursor.Next() { result := query.Result{} key := datastore.NewKey(string(k)) result.Entry.Key = key.String() if !q.KeysOnly { - result.Entry.Value, result.Error = d.Get(key) + result.Entry.Value = v } // initiate a non-blocking channel send select {