2014-07-30 18:30:38 +02:00
|
|
|
// Copyright (c) 2014 Couchbase, Inc.
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
|
|
|
// except in compliance with the License. You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
// Unless required by applicable law or agreed to in writing, software distributed under the
|
|
|
|
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
|
|
// either express or implied. See the License for the specific language governing permissions
|
|
|
|
// and limitations under the License.
|
2014-05-09 22:37:04 +02:00
|
|
|
package gouchstore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/mschoch/gouchstore"
|
|
|
|
)
|
|
|
|
|
|
|
|
type GouchstoreIterator struct {
|
|
|
|
store *GouchstoreStore
|
|
|
|
valid bool
|
|
|
|
curr *gouchstore.DocumentInfo
|
|
|
|
diChan chan *gouchstore.DocumentInfo
|
|
|
|
closeChan chan bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func newGouchstoreIterator(store *GouchstoreStore) *GouchstoreIterator {
|
|
|
|
rv := GouchstoreIterator{
|
|
|
|
store: store,
|
|
|
|
}
|
|
|
|
return &rv
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) cleanupExistingIterator() {
|
|
|
|
if gi.closeChan != nil {
|
|
|
|
close(gi.closeChan)
|
|
|
|
alive := true
|
|
|
|
for alive {
|
|
|
|
_, alive = <-gi.diChan
|
|
|
|
}
|
|
|
|
gi.closeChan = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) SeekFirst() {
|
|
|
|
gi.Seek([]byte{})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) Seek(key []byte) {
|
|
|
|
gi.cleanupExistingIterator()
|
|
|
|
gi.curr = nil
|
|
|
|
gi.diChan = make(chan *gouchstore.DocumentInfo)
|
|
|
|
gi.closeChan = make(chan bool)
|
|
|
|
|
|
|
|
wtCallback := func(gouchstore *gouchstore.Gouchstore, depth int, documentInfo *gouchstore.DocumentInfo, key []byte, subTreeSize uint64, reducedValue []byte, userContext interface{}) error {
|
|
|
|
|
|
|
|
if documentInfo != nil && documentInfo.Deleted == false {
|
|
|
|
select {
|
|
|
|
case gi.diChan <- documentInfo:
|
|
|
|
gi.valid = true
|
|
|
|
case <-gi.closeChan:
|
|
|
|
return fmt.Errorf("seek aborted")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
gi.store.db.WalkIdTree(string(key), "", wtCallback, nil)
|
|
|
|
close(gi.diChan)
|
|
|
|
}()
|
|
|
|
gi.curr = <-gi.diChan
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) Current() ([]byte, []byte, bool) {
|
|
|
|
if gi.Valid() {
|
|
|
|
return gi.Key(), gi.Value(), true
|
|
|
|
}
|
|
|
|
return nil, nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) Next() {
|
|
|
|
gi.curr = <-gi.diChan
|
|
|
|
if gi.curr == nil {
|
|
|
|
gi.valid = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) Key() []byte {
|
|
|
|
if gi.curr != nil {
|
|
|
|
return []byte(gi.curr.ID)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) Value() []byte {
|
|
|
|
if gi.curr != nil {
|
|
|
|
doc, err := gi.store.db.DocumentByDocumentInfo(gi.curr)
|
|
|
|
if err == nil {
|
|
|
|
return doc.Body
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) Valid() bool {
|
|
|
|
return gi.valid
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gi *GouchstoreIterator) Close() {
|
|
|
|
gi.cleanupExistingIterator()
|
|
|
|
}
|