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,33 @@ func (a *accessor) Delete(key ds.Key) (err error) {
114113}
115114
116115func (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
117+
118+ // make a copy of the query for the fallback naive query implementation.
119+ // don't modify the original so res.Query() returns the correct results.
120+ qNaive := q
128121 if q .Prefix != "" {
129122 rnge = util .BytesPrefix ([]byte (q .Prefix ))
123+ qNaive .Prefix = ""
130124 }
131125 i := a .ldb .NewIterator (rnge , nil )
132- return dsq .ResultsFromIterator (q , dsq.Iterator {
126+ next := i .Next
127+ if len (q .Orders ) > 0 {
128+ switch q .Orders [0 ].(type ) {
129+ case dsq.OrderByKey , * dsq.OrderByKey :
130+ qNaive .Orders = nil
131+ case dsq.OrderByKeyDescending , * dsq.OrderByKeyDescending :
132+ next = func () bool {
133+ next = i .Prev
134+ return i .Last ()
135+ }
136+ qNaive .Orders = nil
137+ default :
138+ }
139+ }
140+ r := dsq .ResultsFromIterator (q , dsq.Iterator {
133141 Next : func () (dsq.Result , bool ) {
134- ok := i .Next ()
135- if ! ok {
142+ if ! next () {
136143 return dsq.Result {}, false
137144 }
138145 k := string (i .Key ())
@@ -149,86 +156,8 @@ func (a *accessor) queryNew(q dsq.Query) (dsq.Results, error) {
149156 i .Release ()
150157 return nil
151158 },
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 )
166159 })
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- }
160+ return dsq .NaiveQueryApply (qNaive , r ), nil
232161}
233162
234163// DiskUsage returns the current disk size used by this levelDB.
0 commit comments