Exemple #1
0
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
}
Exemple #2
0
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
}
Exemple #3
0
// 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])
	}
}
Exemple #4
0
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
}
Exemple #5
0
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
}
Exemple #6
0
func (rows ViewRows) Less(i, j int) bool {
	return walrus.CollateJSON(rows[i].Key, rows[j].Key) < 0
}