예제 #1
0
파일: schema.go 프로젝트: l-k-/origins
// Facts encodes the schema as facts. This is primarily used for programmatically
// creating a schema and then writing the facts to storage for later use.
func (s *Schema) Facts() origins.Facts {
	var (
		err    error
		attr   *Attribute
		fact   *origins.Fact
		facts  origins.Facts
		buf    = origins.NewBuffer(nil)
		entity *origins.Ident
	)

	for _, attr = range s.attrs {
		entity = &origins.Ident{
			Domain: attr.Domain,
			Name:   attr.Name,
		}

		if facts, err = origins.Reflect(attr); err != nil {
			panic(err)
		}

		for _, fact = range facts {
			fact.Domain = s.Domain
			fact.Entity = entity

			// Fill in the defaults.
			if fact.Attribute.Domain == "" {
				fact.Attribute.Domain = fact.Domain
			}

			buf.Write(fact)
		}
	}

	return buf.Facts()
}
예제 #2
0
파일: pipeline.go 프로젝트: l-k-/origins
// Handle takes a fact and returns an error if the fact cannot be handled.
func (p *Pipeline) Handle(fact *origins.Fact) error {
	// Do not dedupe.
	if !p.dedupe {
		return p.segment.Write(fact)
	}

	// Initialize the cache.
	if !p.initialized {
		if err := p.initCache(); err != nil {
			return err
		}
	}

	// First transaction of the domain, write everything.
	if p.cache == nil {
		return p.segment.Write(fact)
	}

	var (
		ok    bool
		facts origins.Facts
		value interface{}
	)

	// Lookup the fact by name in the cache to get the facts.
	if value, ok = p.cache.Lookup([]byte(fact.Entity.Name)); !ok {
		return p.segment.Write(fact)
	}

	// Type assert to facts.
	facts = value.(origins.Facts)

	// Entity exists, check for an existing attribute.
	prev := origins.First(origins.NewBuffer(facts), func(f *origins.Fact) bool {
		return f.Attribute.Is(fact.Attribute)
	})

	// New attribute for entity.
	if prev == nil {
		return p.segment.Write(fact)
	}

	// Compare the values.
	if fact.Value.Is(prev.Value) && fact.Operation == prev.Operation {
		return nil
	}

	return p.segment.Write(fact)
}
예제 #3
0
파일: pipeline.go 프로젝트: l-k-/origins
func (p *Pipeline) initCache() error {
	logrus.Debugf("transactor.Pipeline(%s): initializing cache", p.Domain)

	p.initialized = true

	log, err := view.OpenLog(p.engine, p.Domain, commitLogName)

	// This denotes the domain is new.
	if err == view.ErrDoesNotExist {
		return nil
	} else if err != nil {
		return err
	}

	facts, err := origins.ReadAll(log.Asof(p.segment.Time))

	if err != nil {
		return err
	}

	// Sort facts by entity.
	origins.Timsort(facts, origins.EAVTComparator)

	// Group the facts by entity.
	giter := origins.Groupby(origins.NewBuffer(facts), func(f1, f2 *origins.Fact) bool {
		return f1.Entity.Is(f2.Entity)
	})

	// Initializing ctrie.
	cache := ctrie.New(nil)

	err = origins.MapFacts(giter, func(facts origins.Facts) error {
		cache.Insert([]byte(facts[0].Entity.Name), facts)
		return nil
	})

	p.cache = cache

	logrus.Debugf("transactor.Pipeline(%s): cache initialized", p.Domain)

	return err
}