/* * EliasDB * * Copyright 2016 Matthias Ladkau. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package graph import ( "fmt" "sort" "strconv" "sync" "devt.de/krotik/eliasdb/graph/data" "devt.de/krotik/eliasdb/graph/graphstorage" "devt.de/krotik/eliasdb/graph/util" ) /* Manager data structure */ type Manager struct { gs graphstorage.Storage // Graph storage of this graph manager gr *graphRulesManager // Manager for graph rules nm *util.NamesManager // Manager object which manages name encodings mapCache map[string]map[string]string // Cache which caches maps stored in the main database mutex *sync.RWMutex // Mutex to protect atomic graph operations storageMutex *sync.Mutex // Special mutex for storage object access } /* NewGraphManager returns a new GraphManager instance. */ func NewGraphManager(gs graphstorage.Storage) *Manager { gm := createGraphManager(gs) gm.SetGraphRule(&SystemRuleDeleteNodeEdges{}) gm.SetGraphRule(&SystemRuleUpdateNodeStats{}) return gm } /* createGraphManager creates a new GraphManager instance. */ func createGraphManager(gs graphstorage.Storage) *Manager { mdb := gs.MainDB() // Check version if version, ok := mdb[MainDBVersion]; !ok { mdb[MainDBVersion] = strconv.Itoa(VERSION) gs.FlushMain() } else { if v, _ := strconv.Atoi(version); v > VERSION { panic(fmt.Sprintf("Cannot open graph storage of version: %v - "+ "max supported version: %v", version, VERSION)) } else if v < VERSION { // Update the version if it is older mdb[MainDBVersion] = strconv.Itoa(VERSION) gs.FlushMain() } } gm := &Manager{gs, &graphRulesManager{nil, make(map[string]Rule), make(map[int]map[string]Rule)}, util.NewNamesManager(mdb), make(map[string]map[string]string), &sync.RWMutex{}, &sync.Mutex{}} gm.gr.gm = gm return gm } /* Name returns the name of this graph manager. */ func (gm *Manager) Name() string { return fmt.Sprint("Graph ", gm.gs.Name()) } /* SetGraphRule sets a GraphRule. */ func (gm *Manager) SetGraphRule(rule Rule) { gm.gr.SetGraphRule(rule) } /* GraphRules returns a list of all available graph rules. */ func (gm *Manager) GraphRules() []string { return gm.gr.GraphRules() } /* NodeIndexQuery returns an object to query the full text search index for nodes. */ func (gm *Manager) NodeIndexQuery(part string, kind string) (IndexQuery, error) { iht, err := gm.getNodeIndexHTree(part, kind, false) if err != nil || iht == nil { return nil, err } return util.NewIndexManager(iht), nil } /* EdgeIndexQuery returns an object to query the full text search index for edges. */ func (gm *Manager) EdgeIndexQuery(part string, kind string) (IndexQuery, error) { iht, err := gm.getEdgeIndexHTree(part, kind, false) if err != nil || iht == nil { return nil, err } return util.NewIndexManager(iht), nil } /* Partitions returns all existing partitions. */ func (gm *Manager) Partitions() []string { return gm.mainStringList(MainDBParts) } /* NodeKinds returns all possible node kinds. */ func (gm *Manager) NodeKinds() []string { return gm.mainStringList(MainDBNodeKinds) } /* EdgeKinds returns all possible node kinds. */ func (gm *Manager) EdgeKinds() []string { return gm.mainStringList(MainDBEdgeKinds) } /* NodeAttrs returns all possible node attributes for a given node kind. */ func (gm *Manager) NodeAttrs(kind string) []string { return gm.mainStringList(MainDBNodeAttrs + kind) } /* NodeEdges returns all possible node edge specs for a given node kind. */ func (gm *Manager) NodeEdges(kind string) []string { return gm.mainStringList(MainDBNodeEdges + kind) } /* EdgeAttrs returns all possible edge attributes for a given edge kind. */ func (gm *Manager) EdgeAttrs(kind string) []string { return gm.mainStringList(MainDBEdgeAttrs + kind) } /* mainStringList return a list in the MainDB. */ func (gm *Manager) mainStringList(name string) []string { items := gm.getMainDBMap(name) var ret []string if items != nil { for item := range items { ret = append(ret, item) } } sort.StringSlice(ret).Sort() return ret } /* IsValidAttr checks if a given string can be a valid node attribute. */ func (gm *Manager) IsValidAttr(attr string) bool { return gm.nm.Encode32(attr, false) != "" || attr == data.NodeKey || attr == data.NodeKind || attr == data.EdgeEnd1Key || attr == data.EdgeEnd1Kind || attr == data.EdgeEnd1Role || attr == data.EdgeEnd1Cascading || attr == data.EdgeEnd2Key || attr == data.EdgeEnd2Kind || attr == data.EdgeEnd2Role || attr == data.EdgeEnd2Cascading }