// 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() }
// 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) }
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 }