Skip to content

Commit b503c74

Browse files
committed
optimize reverse-sorted query
1 parent 253c31f commit b503c74

File tree

3 files changed

+21
-97
lines changed

3 files changed

+21
-97
lines changed

datastore.go

Lines changed: 18 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66

77
ds "github.com/ipfs/go-datastore"
88
dsq "github.com/ipfs/go-datastore/query"
9-
"github.com/jbenet/goprocess"
109
"github.com/syndtr/goleveldb/leveldb"
1110
"github.com/syndtr/goleveldb/leveldb/errors"
1211
"github.com/syndtr/goleveldb/leveldb/iterator"
@@ -114,25 +113,29 @@ func (a *accessor) Delete(key ds.Key) (err error) {
114113
}
115114

116115
func (a *accessor) Query(q dsq.Query) (dsq.Results, error) {
117-
return a.queryNew(q)
118-
}
119-
120-
func (a *accessor) queryNew(q dsq.Query) (dsq.Results, error) {
121-
if len(q.Filters) > 0 ||
122-
len(q.Orders) > 0 ||
123-
q.Limit > 0 ||
124-
q.Offset > 0 {
125-
return a.queryOrig(q)
126-
}
127116
var rnge *util.Range
128117
if q.Prefix != "" {
129118
rnge = util.BytesPrefix([]byte(q.Prefix))
119+
q.Prefix = ""
130120
}
131121
i := a.ldb.NewIterator(rnge, nil)
132-
return dsq.ResultsFromIterator(q, dsq.Iterator{
122+
next := i.Next
123+
if len(q.Orders) > 0 {
124+
switch q.Orders[0].(type) {
125+
case dsq.OrderByKey, *dsq.OrderByKey:
126+
q.Orders = nil
127+
case dsq.OrderByKeyDescending, *dsq.OrderByKeyDescending:
128+
next = func() bool {
129+
next = i.Prev
130+
return i.Last()
131+
}
132+
q.Orders = nil
133+
default:
134+
}
135+
}
136+
r := dsq.ResultsFromIterator(q, dsq.Iterator{
133137
Next: func() (dsq.Result, bool) {
134-
ok := i.Next()
135-
if !ok {
138+
if !next() {
136139
return dsq.Result{}, false
137140
}
138141
k := string(i.Key())
@@ -149,86 +152,8 @@ func (a *accessor) queryNew(q dsq.Query) (dsq.Results, error) {
149152
i.Release()
150153
return nil
151154
},
152-
}), nil
153-
}
154-
155-
func (a *accessor) queryOrig(q dsq.Query) (dsq.Results, error) {
156-
// we can use multiple iterators concurrently. see:
157-
// https://godoc.org/github.com/syndtr/goleveldb/leveldb#DB.NewIterator
158-
// advance the iterator only if the reader reads
159-
//
160-
// run query in own sub-process tied to Results.Process(), so that
161-
// it waits for us to finish AND so that clients can signal to us
162-
// that resources should be reclaimed.
163-
qrb := dsq.NewResultBuilder(q)
164-
qrb.Process.Go(func(worker goprocess.Process) {
165-
a.runQuery(worker, qrb)
166155
})
167-
168-
// go wait on the worker (without signaling close)
169-
go qrb.Process.CloseAfterChildren()
170-
171-
// Now, apply remaining things (filters, order)
172-
qr := qrb.Results()
173-
for _, f := range q.Filters {
174-
qr = dsq.NaiveFilter(qr, f)
175-
}
176-
if len(q.Orders) > 0 {
177-
switch q.Orders[0].(type) {
178-
case dsq.OrderByKey, *dsq.OrderByKey:
179-
// Default ordering
180-
default:
181-
qr = dsq.NaiveOrder(qr, q.Orders...)
182-
}
183-
}
184-
return qr, nil
185-
}
186-
187-
func (a *accessor) runQuery(worker goprocess.Process, qrb *dsq.ResultBuilder) {
188-
var rnge *util.Range
189-
if qrb.Query.Prefix != "" {
190-
rnge = util.BytesPrefix([]byte(qrb.Query.Prefix))
191-
}
192-
i := a.ldb.NewIterator(rnge, nil)
193-
defer i.Release()
194-
195-
// advance iterator for offset
196-
if qrb.Query.Offset > 0 {
197-
for j := 0; j < qrb.Query.Offset; j++ {
198-
i.Next()
199-
}
200-
}
201-
202-
// iterate, and handle limit, too
203-
for sent := 0; i.Next(); sent++ {
204-
// end early if we hit the limit
205-
if qrb.Query.Limit > 0 && sent >= qrb.Query.Limit {
206-
break
207-
}
208-
209-
k := string(i.Key())
210-
e := dsq.Entry{Key: k}
211-
212-
if !qrb.Query.KeysOnly {
213-
buf := make([]byte, len(i.Value()))
214-
copy(buf, i.Value())
215-
e.Value = buf
216-
}
217-
218-
select {
219-
case qrb.Output <- dsq.Result{Entry: e}: // we sent it out
220-
case <-worker.Closing(): // client told us to end early.
221-
break
222-
}
223-
}
224-
225-
if err := i.Error(); err != nil {
226-
select {
227-
case qrb.Output <- dsq.Result{Error: err}: // client read our error
228-
case <-worker.Closing(): // client told us to end.
229-
return
230-
}
231-
}
156+
return dsq.NaiveQueryApply(q, r), nil
232157
}
233158

234159
// DiskUsage returns the current disk size used by this levelDB.

go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
module github.com/ipfs/go-ds-leveldb
22

33
require (
4-
github.com/ipfs/go-datastore v0.0.1
5-
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8
4+
github.com/ipfs/go-datastore v0.0.3
65
github.com/syndtr/goleveldb v1.0.0
76
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
1010
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
1111
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
1212
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
13-
github.com/ipfs/go-datastore v0.0.1 h1:AW/KZCScnBWlSb5JbnEnLKFWXL224LBEh/9KXXOrUms=
14-
github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
13+
github.com/ipfs/go-datastore v0.0.3 h1:/eP3nMDmLzMJNoWSSYvEkmMTTrm9FFCN+JraP9NdlwU=
14+
github.com/ipfs/go-datastore v0.0.3/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
1515
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
1616
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw=
1717
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=

0 commit comments

Comments
 (0)