func (bd *boltDatastore) Query(q query.Query) (query.Results, error) { qrb := query.NewResultBuilder(q) qrb.Process.Go(func(worker goprocess.Process) { bd.db.View(func(tx *bolt.Tx) error { buck := tx.Bucket(bd.bucketName) c := buck.Cursor() var prefix []byte if qrb.Query.Prefix != "" { prefix = []byte(qrb.Query.Prefix) } cur := 0 sent := 0 for k, v := c.Seek(prefix); k != nil; k, v = c.Next() { if cur < qrb.Query.Offset { cur++ continue } if qrb.Query.Limit > 0 && sent >= qrb.Query.Limit { break } dk := ds.NewKey(string(k)).String() e := query.Entry{Key: dk} if !qrb.Query.KeysOnly { buf := make([]byte, len(v)) copy(buf, v) e.Value = buf } select { case qrb.Output <- query.Result{Entry: e}: // we sent it out sent++ case <-worker.Closing(): // client told us to end early. break } cur++ } return nil }) }) // go wait on the worker (without signaling close) go qrb.Process.CloseAfterChildren() qr := qrb.Results() for _, f := range q.Filters { qr = query.NaiveFilter(qr, f) } for _, o := range q.Orders { qr = query.NaiveOrder(qr, o) } return qr, nil }
func (d *datastore) runQuery(worker goprocess.Process, qrb *dsq.ResultBuilder) { var rnge *util.Range if qrb.Query.Prefix != "" { rnge = util.BytesPrefix([]byte(qrb.Query.Prefix)) } i := d.DB.NewIterator(rnge, nil) defer i.Release() // advance iterator for offset if qrb.Query.Offset > 0 { for j := 0; j < qrb.Query.Offset; j++ { i.Next() } } // iterate, and handle limit, too for sent := 0; i.Next(); sent++ { // end early if we hit the limit if qrb.Query.Limit > 0 && sent >= qrb.Query.Limit { break } k := ds.NewKey(string(i.Key())).String() e := dsq.Entry{Key: k} if !qrb.Query.KeysOnly { buf := make([]byte, len(i.Value())) copy(buf, i.Value()) e.Value = buf } select { case qrb.Output <- dsq.Result{Entry: e}: // we sent it out case <-worker.Closing(): // client told us to end early. break } } if err := i.Error(); err != nil { select { case qrb.Output <- dsq.Result{Error: err}: // client read our error case <-worker.Closing(): // client told us to end. return } } }