Esempio n. 1
0
// Test the Next() method for the given iterator.
// Return the number of elements encountered.
func testNext(iter origins.Iterator) (int, error) {
	var (
		i int
		f *origins.Fact
	)

	for {
		if f = iter.Next(); f == nil {
			break
		}

		i++
	}

	if err := iter.Err(); err != nil {
		return 0, err
	}

	return i, nil
}
Esempio n. 2
0
// Timeline returns an ordered set of events derived from the fact iterator.
// The iterator is assumed to return facts in reverse order by time (newest first)
// which is what the Log view returns.
func Timeline(iter origins.Iterator, order Order) ([]*Event, error) {
	var (
		key              [4]string
		err              error
		fact, prev, next *origins.Fact
		events           []*Event
		event            *Event
		etype            EventType
	)

	// Map facts keyed by entity/attribute pairs.
	// TODO: benchmark compared to cached identity approach. This is more
	// resilient since it does not rely on pointers.
	facts := make(map[[4]string]*origins.Fact)

	for {
		if fact = iter.Next(); fact == nil {
			break
		}

		// Uniquely identities an entity-attribute pair. The fact domain
		// is not considered here since that can be controlled by the passed
		// iterator.
		key = [4]string{
			fact.Entity.Domain,
			fact.Entity.Name,
			fact.Attribute.Domain,
			fact.Attribute.Name,
		}

		// Swap depending on order.
		switch order {
		case Ascending:
			next = fact
			prev = facts[key]
		case Descending:
			prev = fact
			next = facts[key]
		default:
			logrus.Panicf("view: unknown order %v", order)
		}

		// Update the cache with the current fact.
		facts[key] = fact

		// No existing fact. Construct add event
		if prev == nil || next == nil {
			etype = Add

			// The next fact is a retraction. Since facts are ordered by
			// time, this assumes the retraction applies to the same value.
		} else if next.Operation == origins.Retraction {
			etype = Remove

			// If the value differs, mark as a change event.
		} else if !next.Value.Is(prev.Value) {
			etype = Change

			// Last condition assumes the fact is a duplicate.
		} else {
			continue
		}

		// Construct the event.
		event = &Event{
			Type:      etype,
			Entity:    fact.Entity,
			Attribute: fact.Attribute,
			Before:    prev,
			After:     next,
		}

		events = append(events, event)
	}

	if err = iter.Err(); err != nil {
		return nil, err
	}

	// TODO: The final set of facts represent the current state
	// (ascending) or initial state (descending) of the iterator.

	return events, nil
}