func processViewResult(bucket Bucket, result *ViewResult, p *ViewParams) (*ViewResult, error) { if p.Key != nil { p.StartKey = p.Key p.EndKey = p.Key } if p.StartKey != nil { i := sort.Search(len(result.Rows), func(i int) bool { return walrus.CollateJSON(result.Rows[i].Key, p.StartKey) >= 0 }) if p.Descending { result.Rows = result.Rows[:i+1] } else { result.Rows = result.Rows[i:] } } if p.EndKey != nil { i := sort.Search(len(result.Rows), func(i int) bool { if p.InclusiveEnd { return walrus.CollateJSON(result.Rows[i].Key, p.EndKey) > 0 } return walrus.CollateJSON(result.Rows[i].Key, p.EndKey) >= 0 }) if p.Descending { result.Rows = result.Rows[i:] } else { result.Rows = result.Rows[:i] } } if p.Descending { reverseViewRows(result.Rows) } return result, nil }
func vindexKeyCompare(a, b []byte) int { docIdA, emitKeyA, err := vindexKeyParse(a) if err != nil { return bytes.Compare(a, b) } docIdB, emitKeyB, err := vindexKeyParse(b) if err != nil { return bytes.Compare(a, b) } c := walrus.CollateJSON(emitKeyA, emitKeyB) if c == 0 { return bytes.Compare(docIdA, docIdB) } return c }
// Merge incoming, sorted ViewRows by Key. func MergeViewRows(inSorted []chan *ViewRow, out chan *ViewRow) { end := &ViewRow{} // Sentinel. arr := make([]*ViewRow, len(inSorted)) receiveViewRow := func(i int, in chan *ViewRow) { v, ok := <-in if !ok { arr[i] = end } else { arr[i] = v } } for i, in := range inSorted { // Initialize the arr. receiveViewRow(i, in) } pickLeast := func() (int, *ViewRow) { // TODO: Inefficient to iterate over array every time. // [probably more inefficient to have this be a // closure, but should measure to be certain] ileast := -1 vleast := end for i, v := range arr { if vleast == end { ileast = i vleast = v } else if v != end { if walrus.CollateJSON(vleast.Key, v.Key) > 0 { ileast = i vleast = v } } } return ileast, vleast } for { i, v := pickLeast() if v == end { close(out) return } out <- v receiveViewRow(i, inSorted[i]) } }
func reduceViewResult(bucket Bucket, result *ViewResult, p *ViewParams, reduceFunction string) (*ViewResult, error) { groupLevel := 0 if p.Group { groupLevel = 0x7fffffff } if p.GroupLevel > 0 { groupLevel = int(p.GroupLevel) } o := newReducer() fnv, err := OttoNewFunction(o, reduceFunction) if err != nil { return result, err } initialCapacity := 200 results := make([]*ViewRow, 0, initialCapacity) groupKeys := make([]interface{}, 0, initialCapacity) groupValues := make([]interface{}, 0, initialCapacity) i := 0 j := 0 for i < len(result.Rows) { groupKeys = groupKeys[:0] groupValues = groupValues[:0] startRow := result.Rows[i] groupKey := ArrayPrefix(startRow.Key, groupLevel) for j = i; j < len(result.Rows); j++ { row := result.Rows[j] rowKey := ArrayPrefix(row.Key, groupLevel) if walrus.CollateJSON(groupKey, rowKey) < 0 { break } groupKeys = append(groupKeys, row.Key) groupValues = append(groupValues, row.Value) } i = j okeys, err := OttoFromGoArray(o, groupKeys) if err != nil { return result, err } ovalues, err := OttoFromGoArray(o, groupValues) if err != nil { return result, err } ores, err := fnv.Call(fnv, okeys, ovalues, otto.FalseValue()) if err != nil { return result, fmt.Errorf("call reduce err: %v, reduceFunction: %v, %v, %v", err, reduceFunction, okeys, ovalues) } gres, err := ores.Export() if err != nil { return result, fmt.Errorf("converting reduce result err: %v", err) } results = append(results, &ViewRow{Key: groupKey, Value: gres}) } result.Rows = results return result, nil }
func visitVIndex(vb *VBucket, ddocId string, viewId string, p *ViewParams, ch chan *ViewRow, errs chan<- error) { defer close(ch) if vb == nil { errs <- fmt.Errorf("no vbucket during visitVIndex(), ddocId: %v, viewId: %v", ddocId, viewId) return } switch p.Stale { case "false": _, err := vb.viewsRefresh() if err != nil { errs <- err return } case "update_after": // Asynchronously start view updates after finishing // this request. defer func() { go vb.viewsRefresh() }() } viewsStore, err := vb.getViewsStore() if err != nil { errs <- err return } vindex := viewsStore.coll("_design/" + ddocId + "/" + viewId + VINDEX_COLL_SUFFIX) if vindex == nil { errs <- fmt.Errorf("no vindex during visitVIndex(), ddocId: %v, viewId: %v", ddocId, viewId) return } var begKey interface{} var begKeyBytes []byte var endKey interface{} if p.Key != nil { p.StartKey = p.Key p.EndKey = p.Key } if p.Descending { begKey = p.EndKey endKey = p.StartKey } else { begKey = p.StartKey endKey = p.EndKey } if begKey != nil { begKeyBytes, err = vindexKey(nil, begKey) if err != nil { errs <- err return } } if bytes.Equal(begKeyBytes, []byte("null\x00")) { begKeyBytes = nil } errVisit := vindex.VisitItemsAscend(begKeyBytes, true, func(i *gkvlite.Item) bool { docId, emitKey, err := vindexKeyParse(i.Key) if err != nil { return false } if endKey != nil && walrus.CollateJSON(emitKey, endKey) > 0 { return false } var emitValue interface{} err = jsonUnmarshal(i.Val, &emitValue) if err != nil { return false } ch <- &ViewRow{ Id: string(docId), Key: emitKey, Value: emitValue, } return true }) if p.Stale == "update_after" { vb.markStale() } if errVisit != nil { errs <- errVisit return } errs <- err }
func (rows ViewRows) Less(i, j int) bool { return walrus.CollateJSON(rows[i].Key, rows[j].Key) < 0 }