func makeResponsehandler( client *qclient.GsiClient, conn *datastore.IndexConnection) qclient.ResponseHandler { entryChannel := conn.EntryChannel() stopChannel := conn.StopChannel() return func(data qclient.ResponseReader) bool { if err := data.Error(); err != nil { conn.Error(n1qlError(client, err)) return false } skeys, pkeys, err := data.GetEntries() if err == nil { for i, skey := range skeys { // Primary-key is mandatory. e := &datastore.IndexEntry{ PrimaryKey: string(pkeys[i]), } e.EntryKey = skey2Values(skey) fmsg := "current enqueued length: %d (max %d)\n" l.Tracef(fmsg, len(entryChannel), cap(entryChannel)) select { case entryChannel <- e: case <-stopChannel: return false } } return true } conn.Error(errors.NewError(nil, err.Error())) return false } }
func (vi *viewIndex) Scan(requestId string, span *datastore.Span, distinct bool, limit int64, cons datastore.ScanConsistency, vector timestamp.Vector, conn *datastore.IndexConnection) { defer close(conn.EntryChannel()) // For primary indexes, bounds must always be strings, so we // can just enforce that directly viewOptions := map[string]interface{}{} viewOptions = generateViewOptions(cons, span) /*span.Range.Low, span.Range.High, span.Range.Inclusion) */ viewRowChannel := make(chan cb.ViewRow) viewErrChannel := make(chan errors.Error) doneChannel := make(chan bool) defer close(doneChannel) go WalkViewInBatches(viewRowChannel, viewErrChannel, doneChannel, vi.keyspace.cbbucket, vi.DDocName(), vi.ViewName(), vi.IsPrimary(), viewOptions, _BATCH_SIZE, limit) var viewRow cb.ViewRow var err errors.Error sentRows := false ok := true numRows := 0 errs := make([]error, 0, 10) for ok { select { case viewRow, ok = <-viewRowChannel: if ok { entry := datastore.IndexEntry{PrimaryKey: viewRow.ID} // try to add the view row key as the entry key (unless this is _all_docs) if vi.DDocName() != "" /* FIXME && vi.IsPrimary() == false */ { lookupValue, err := convertCouchbaseViewKeyToLookupValue(viewRow.Key) if err == nil { entry.EntryKey = lookupValue } else { errs = append(errs, fmt.Errorf("unable to convert index key to lookup value err:%v key %v", err, entry)) } } select { case conn.EntryChannel() <- &entry: sentRows = true numRows++ case <-conn.StopChannel(): logging.Debugf(" Asked to stop after sending %v rows", numRows) ok = false } } case err, ok = <-viewErrChannel: if err != nil { logging.Errorf("%v", err) // check to possibly detect a bucket that was already deleted if !sentRows { logging.Debugf("Checking bucket URI: %v", vi.keyspace.cbbucket.URI) _, err := http.Get(vi.keyspace.cbbucket.URI) if err != nil { logging.Errorf("%v", err) // remove this specific bucket from the pool cache vi.keyspace.namespace.lock.Lock() delete(vi.keyspace.namespace.keyspaceCache, vi.keyspace.Name()) vi.keyspace.namespace.lock.Unlock() // close this bucket vi.keyspace.Release() // ask the pool to refresh vi.keyspace.namespace.refresh(true) // bucket doesnt exist any more conn.Error(errors.NewCbViewsAccessError(nil, "keyspace "+vi.keyspace.Name()+" or view index missing")) return } } conn.Error(err) return } } } if errs != nil { logging.Debugf("Errors with converting lookup value to entry key. num errrs %v", len(errs)) } logging.Debugf("Number of entries fetched from the index %d", numRows) }
func notifyConn(conn *datastore.IndexConnection) { select { case conn.StopChannel() <- false: default: } }