VOL-1027 : Initial commit of voltha 2.0 data model
Change-Id: Ib8006de1af2166281ccf1c9d7c2b9156991bf4e4
diff --git a/db/model/root.go b/db/model/root.go
new file mode 100644
index 0000000..722fc94
--- /dev/null
+++ b/db/model/root.go
@@ -0,0 +1,213 @@
+package model
+
+import (
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "github.com/google/uuid"
+ "reflect"
+)
+
+type Root struct {
+ *Node
+ DirtyNodes map[string]*Node
+ KvStore *Backend
+ Loading bool
+ RevisionClass interface{}
+ Callbacks []func() interface{}
+ NotificationCallbacks []func() interface{}
+}
+
+func NewRoot(initialData interface{}, kvStore *Backend, revisionClass interface{}) *Root {
+ root := &Root{}
+ root.KvStore = kvStore
+ root.DirtyNodes = make(map[string]*Node)
+ root.Loading = false
+ if kvStore != nil /*&& FIXME: RevisionClass is a subclass of PersistedConfigRevision */ {
+ revisionClass = reflect.TypeOf(PersistedRevision{})
+ }
+ root.RevisionClass = revisionClass
+ root.Callbacks = []func() interface{}{}
+ root.NotificationCallbacks = []func() interface{}{}
+
+ root.Node = NewNode(root, initialData, false, "")
+
+ return root
+}
+
+func (r *Root) makeRevision(branch *Branch, data interface{}, children map[string][]*Revision) *Revision {
+
+ return &Revision{}
+}
+
+func (r *Root) makeTxBranch() string {
+ txid_bin, _ := uuid.New().MarshalBinary()
+ txid := hex.EncodeToString(txid_bin)[:12]
+ r.DirtyNodes[txid] = r.Node
+ r.Node.makeTxBranch(txid)
+ return txid
+}
+
+func (r *Root) deleteTxBranch(txid string) {
+ for _, dirtyNode := range r.DirtyNodes {
+ dirtyNode.deleteTxBranch(txid)
+ }
+ delete(r.DirtyNodes, txid)
+}
+
+func (r *Root) foldTxBranch(txid string) {
+ // TODO: implement foldTxBranch
+ // if err := r.Node.mergeTxBranch(txid, dryRun=true); err != nil {
+ // r.deleteTxBranch(txid)
+ // } else {
+ // r.Node.mergeTxBranch(txid)
+ // r.executeCallbacks()
+ // }
+}
+
+func (r *Root) executeCallbacks() {
+ for len(r.Callbacks) > 0 {
+ callback := r.Callbacks[0]
+ r.Callbacks = r.Callbacks[1:]
+ callback()
+ }
+ for len(r.NotificationCallbacks) > 0 {
+ callback := r.NotificationCallbacks[0]
+ r.NotificationCallbacks = r.NotificationCallbacks[1:]
+ callback()
+ }
+}
+
+func (r *Root) noCallbacks() bool {
+ return len(r.Callbacks) == 0
+}
+
+func (r *Root) addCallback(callback func() interface{}) {
+ r.Callbacks = append(r.Callbacks, callback)
+}
+func (r *Root) addNotificationCallback(callback func() interface{}) {
+ r.NotificationCallbacks = append(r.NotificationCallbacks, callback)
+}
+
+func (r *Root) Update(path string, data interface{}, strict bool, txid string, makeBranch t_makeBranch) *Revision {
+ var result *Revision
+ // FIXME: the more i look at this... i think i need to implement an interface for Node & root
+
+ if makeBranch == nil {
+ // TODO: raise error
+ }
+
+ if r.noCallbacks() {
+ // TODO: raise error
+ }
+
+ if txid != "" {
+ //dirtied := r.DirtyNodes[txid]
+
+ trackDirty := func(node *Node) *Branch {
+ //dirtied.Add(Node)
+ return node.makeTxBranch(txid)
+ }
+ result = r.Node.Update(path, data, strict, txid, trackDirty)
+ } else {
+ result = r.Node.Update(path, data, strict, "", nil)
+ }
+
+ r.executeCallbacks()
+
+ return result
+}
+
+func (r *Root) Add(path string, data interface{}, txid string, makeBranch t_makeBranch) *Revision {
+ var result *Revision
+ // FIXME: the more i look at this... i think i need to implement an interface for Node & root
+
+ if makeBranch == nil {
+ // TODO: raise error
+ }
+
+ if r.noCallbacks() {
+ // TODO: raise error
+ }
+
+ if txid != "" {
+ //dirtied := r.DirtyNodes[txid]
+
+ trackDirty := func(node *Node) *Branch {
+ //dirtied.Add(Node)
+ return node.makeTxBranch(txid)
+ }
+ result = r.Node.Add(path, data, txid, trackDirty)
+ } else {
+ result = r.Node.Add(path, data, "", nil)
+ }
+
+ r.executeCallbacks()
+
+ return result
+}
+
+func (r *Root) Remove(path string, txid string, makeBranch t_makeBranch) *Revision {
+ var result *Revision
+ // FIXME: the more i look at this... i think i need to implement an interface for Node & root
+
+ if makeBranch == nil {
+ // TODO: raise error
+ }
+
+ if r.noCallbacks() {
+ // TODO: raise error
+ }
+
+ if txid != "" {
+ //dirtied := r.DirtyNodes[txid]
+
+ trackDirty := func(node *Node) *Branch {
+ //dirtied.Add(Node)
+ return node.makeTxBranch(txid)
+ }
+ result = r.Node.Remove(path, txid, trackDirty)
+ } else {
+ result = r.Node.Remove(path, "", nil)
+ }
+
+ r.executeCallbacks()
+
+ return result
+}
+
+func (r *Root) Load(rootClass interface{}) *Root {
+ //fakeKvStore := &Backend{}
+ //root := NewRoot(rootClass, fakeKvStore, PersistedRevision{})
+ //r.KvStore = KvStore
+ r.loadFromPersistence(rootClass)
+ return r
+}
+
+func (r *Root) LoadLatest(hash string) {
+ r.Node.LoadLatest(r.KvStore, hash)
+}
+
+type rootData struct {
+ Latest string `json:GetLatest`
+ Tags map[string]string `json:Tags`
+}
+
+func (r *Root) loadFromPersistence(rootClass interface{}) {
+ var data rootData
+
+ r.Loading = true
+ blob, _ := r.KvStore.Get("root")
+
+ if err := json.Unmarshal(blob.Value.([]byte), &data); err != nil {
+ fmt.Errorf("problem to unmarshal blob - error:%s\n", err.Error())
+ }
+
+ for tag, hash := range data.Tags {
+ r.Node.LoadLatest(r.KvStore, hash)
+ r.Node.Tags[tag] = r.Node.Latest()
+ }
+
+ r.Node.LoadLatest(r.KvStore, data.Latest)
+ r.Loading = false
+}