123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- package graph
- import (
- "sort"
- "strings"
- "sync"
- "devt.de/krotik/eliasdb/graph/data"
- "devt.de/krotik/eliasdb/graph/util"
- )
- type graphRulesManager struct {
- gm *Manager
- rules map[string]Rule
- eventMap map[int]map[string]Rule
- }
- type Rule interface {
-
- Name() string
-
- Handles() []int
-
- Handle(gm *Manager, trans Trans, event int, data ...interface{}) error
- }
- func (gr *graphRulesManager) graphEvent(trans Trans, event int, data ...interface{}) error {
- var result error
- var errors []string
- rules, ok := gr.eventMap[event]
- handled := false
- if ok {
- for _, rule := range rules {
-
- gmclone := gr.cloneGraphManager()
- gmclone.mutex.RLock()
- defer gmclone.mutex.RUnlock()
-
- err := rule.Handle(gmclone, trans, event, data...)
- if err != nil {
- if err == ErrEventHandled {
- handled = true
- } else {
- if errors == nil {
- errors = make([]string, 0)
- }
- errors = append(errors, err.Error())
- }
- }
- }
- }
- if errors != nil {
- return &util.GraphError{Type: util.ErrRule, Detail: strings.Join(errors, ";")}
- }
- if handled {
- result = ErrEventHandled
- }
- return result
- }
- func (gr *graphRulesManager) cloneGraphManager() *Manager {
- return &Manager{gr.gm.gs, gr, gr.gm.nm, gr.gm.mapCache, &sync.RWMutex{}, &sync.Mutex{}}
- }
- func (gr *graphRulesManager) SetGraphRule(rule Rule) {
- gr.rules[rule.Name()] = rule
- for _, handledEvent := range rule.Handles() {
- rules, ok := gr.eventMap[handledEvent]
- if !ok {
- rules = make(map[string]Rule)
- gr.eventMap[handledEvent] = rules
- }
- rules[rule.Name()] = rule
- }
- }
- func (gr *graphRulesManager) GraphRules() []string {
- ret := make([]string, 0, len(gr.rules))
- for rule := range gr.rules {
- ret = append(ret, rule)
- }
- sort.StringSlice(ret).Sort()
- return ret
- }
- type SystemRuleDeleteNodeEdges struct {
- }
- func (r *SystemRuleDeleteNodeEdges) Name() string {
- return "system.deletenodeedges"
- }
- func (r *SystemRuleDeleteNodeEdges) Handles() []int {
- return []int{EventNodeDeleted}
- }
- func (r *SystemRuleDeleteNodeEdges) Handle(gm *Manager, trans Trans, event int, ed ...interface{}) error {
- part := ed[0].(string)
- node := ed[1].(data.Node)
-
- nnodes, edges, err := gm.TraverseMulti(part, node.Key(), node.Kind(), ":::", false)
- if err != nil {
- return err
- }
- edgeRemovalCount := make(map[string]int)
-
- var nodeRemovalCheckNodes []data.Node
- var nodeRemovalCheckSpecs []string
- for i, edge := range edges {
-
- trans.RemoveEdge(part, edge.Key(), edge.Kind())
-
- if edge.End1IsCascading() {
- if edge.End1IsCascadingLast() {
-
-
-
- nodeOtherSide := nnodes[i]
- specOtherSide := edge.Spec(nodeOtherSide.Key())
- if c, ok := edgeRemovalCount[specOtherSide]; ok {
- edgeRemovalCount[specOtherSide] = c + 1
- } else {
- edgeRemovalCount[specOtherSide] = 1
- }
- nodeRemovalCheckSpecs = append(nodeRemovalCheckSpecs, specOtherSide)
- nodeRemovalCheckNodes = append(nodeRemovalCheckNodes, nodeOtherSide)
- } else {
-
-
- trans.RemoveNode(part, nnodes[i].Key(), nnodes[i].Kind())
- }
- }
- }
-
- for i, node := range nodeRemovalCheckNodes {
- specToCheck := nodeRemovalCheckSpecs[i]
- removalCount := edgeRemovalCount[specToCheck]
- if err == nil {
- _, edges, err = gm.TraverseMulti(part, node.Key(), node.Kind(), specToCheck, false)
- if len(edges)-removalCount == 0 {
- trans.RemoveNode(part, node.Key(), node.Kind())
- }
- }
- }
- return err
- }
- type SystemRuleUpdateNodeStats struct {
- }
- func (r *SystemRuleUpdateNodeStats) Name() string {
- return "system.updatenodestats"
- }
- func (r *SystemRuleUpdateNodeStats) Handles() []int {
- return []int{EventNodeCreated, EventNodeUpdated,
- EventEdgeCreated, EventEdgeUpdated}
- }
- func (r *SystemRuleUpdateNodeStats) Handle(gm *Manager, trans Trans, event int, ed ...interface{}) error {
- attrMap := MainDBNodeAttrs
- if event == EventEdgeCreated {
- edge := ed[1].(data.Edge)
- updateNodeRels := func(key string, kind string) {
- spec := edge.Spec(key)
- specs := gm.getMainDBMap(MainDBNodeEdges + kind)
- if specs != nil {
- if _, ok := specs[spec]; !ok {
- specs[spec] = ""
- gm.storeMainDBMap(MainDBNodeEdges+kind, specs)
- }
- }
- }
-
- updateNodeRels(edge.End1Key(), edge.End1Kind())
- updateNodeRels(edge.End2Key(), edge.End2Kind())
- attrMap = MainDBEdgeAttrs
- }
- node := ed[1].(data.Node)
- kind := node.Kind()
-
- if event == EventNodeCreated || event == EventEdgeCreated {
- part := ed[0].(string)
- updateMainDB := func(entry string, val string) {
- vals := gm.getMainDBMap(entry)
- if _, ok := vals[val]; !ok {
- vals[val] = ""
- gm.storeMainDBMap(entry, vals)
- }
- }
- updateMainDB(MainDBParts, part)
- if event == EventNodeCreated {
- updateMainDB(MainDBNodeKinds, kind)
- } else {
- updateMainDB(MainDBEdgeKinds, kind)
- }
- }
- storeAttrs := false
- attrs := gm.getMainDBMap(attrMap + kind)
- if attrs != nil {
-
- for attr := range node.Data() {
- if _, ok := attrs[attr]; !ok {
- attrs[attr] = ""
- storeAttrs = true
- }
- }
-
- if storeAttrs {
- gm.storeMainDBMap(attrMap+kind, attrs)
- }
- }
- return nil
- }
|