VOL-1584: Fix for multi-core cli infinite loop
- Reduced number of calls to kv
- Re-introduced cache logic for in-memory data access
- Misc log updates
Amendments:
- Ensure that we clone the returned cache data
- Give priority to cache but use alternate get methods otherwise
Change-Id: I56ce67f22d9945b7a194f4c6aab0c7fd75dd2f2e
diff --git a/db/model/node.go b/db/model/node.go
index 7bfdca0..9ec5ce9 100644
--- a/db/model/node.go
+++ b/db/model/node.go
@@ -24,7 +24,6 @@
"github.com/golang/protobuf/proto"
"github.com/opencord/voltha-go/common/log"
"reflect"
- "runtime/debug"
"strings"
"sync"
)
@@ -127,6 +126,9 @@
// If anything is new, then set the revision as the latest
if branch.GetLatest() == nil || revision.GetHash() != branch.GetLatest().GetHash() {
+ if revision.GetName() != "" {
+ GetRevCache().Cache.Store(revision.GetName(), revision)
+ }
branch.SetLatest(revision)
}
@@ -275,7 +277,7 @@
var result interface{}
var prList []interface{}
- if pr := rev.LoadFromPersistence(path, txid); pr != nil {
+ if pr := rev.LoadFromPersistence(path, txid, nil); pr != nil {
for _, revEntry := range pr {
prList = append(prList, revEntry.GetData())
}
@@ -288,6 +290,7 @@
// Get retrieves the data from a node tree that resides at the specified path
func (n *node) Get(path string, hash string, depth int, reconcile bool, txid string) interface{} {
log.Debugw("node-get-request", log.Fields{"path": path, "hash": hash, "depth": depth, "reconcile": reconcile, "txid": txid})
+
for strings.HasPrefix(path, "/") {
path = path[1:]
}
@@ -307,9 +310,15 @@
var result interface{}
- // If there is not request to reconcile, try to get it from memory
+ // If there is no request to reconcile, try to get it from memory
if !reconcile {
- if result = n.getPath(rev.GetBranch().GetLatest(), path, depth); result != nil && reflect.ValueOf(result).IsValid() && !reflect.ValueOf(result).IsNil() {
+ // Try to find an entry matching the path value from one of these sources
+ // 1. Start with the cache which stores revisions by watch names
+ // 2. Then look in the revision tree, especially if it's a sub-path such as /devices/1234/flows
+ // 3. As a last effort, move on to the KV store
+ if entry, exists := GetRevCache().Cache.Load(path); exists && entry.(Revision) != nil {
+ return proto.Clone(entry.(Revision).GetData().(proto.Message))
+ } else if result = n.getPath(rev.GetBranch().GetLatest(), path, depth); result != nil && reflect.ValueOf(result).IsValid() && !reflect.ValueOf(result).IsNil() {
return result
}
}
@@ -317,14 +326,14 @@
// If we got to this point, we are either trying to reconcile with the db or
// or we simply failed at getting information from memory
if n.Root.KvStore != nil {
- var prList []interface{}
- if pr := rev.LoadFromPersistence(path, txid); pr != nil && len(pr) > 0 {
+ if pr := rev.LoadFromPersistence(path, txid, nil); pr != nil && len(pr) > 0 {
// Did we receive a single or multiple revisions?
if len(pr) > 1 {
+ var revs []interface{}
for _, revEntry := range pr {
- prList = append(prList, revEntry.GetData())
+ revs = append(revs, revEntry.GetData())
}
- result = prList
+ result = revs
} else {
result = pr[0].GetData()
}
@@ -334,7 +343,7 @@
return result
}
-// getPath traverses the specified path and retrieves the data associated to it
+//getPath traverses the specified path and retrieves the data associated to it
func (n *node) getPath(rev Revision, path string, depth int) interface{} {
if path == "" {
return n.getData(rev, depth)
@@ -472,6 +481,7 @@
idx, childRev := n.findRevByKey(children, field.Key, keyValue)
if childRev == nil {
+ log.Debugw("child-revision-is-nil", log.Fields{"key": keyValue})
return branch.GetLatest()
}
@@ -490,6 +500,7 @@
log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
newChildRev.ClearHash()
}
+ log.Debugw("child-revisions-have-matching-hash", log.Fields{"hash": childRev.GetHash(), "key": keyValue})
return branch.GetLatest()
}
@@ -505,15 +516,15 @@
// Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
newChildRev.SetName(name + "/" + _keyValueType)
+ branch.LatestLock.Lock()
+ defer branch.LatestLock.Unlock()
+
if idx >= 0 {
children[idx] = newChildRev
} else {
children = append(children, newChildRev)
}
- branch.LatestLock.Lock()
- defer branch.LatestLock.Unlock()
-
updatedRev := rev.UpdateChildren(name, children, branch)
n.makeLatest(branch, updatedRev, nil)
@@ -544,13 +555,11 @@
}
func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
- log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
- reflect.TypeOf(data),
- string(debug.Stack()))
+ log.Debugw("comparing-types", log.Fields{"expected": reflect.ValueOf(n.Type).Type(), "actual": reflect.TypeOf(data)})
if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
// TODO raise error
- log.Errorf("data does not match type: %+v", n.Type)
+ log.Errorw("types-do-not-match: %+v", log.Fields{"actual": reflect.TypeOf(data), "expected": n.Type})
return nil
}
@@ -644,6 +653,7 @@
updatedRev := rev.UpdateChildren(name, children, branch)
changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
+ childRev.GetNode().SetProxy(n.GetProxy())
childRev.SetupWatch(childRev.GetName())
n.makeLatest(branch, updatedRev, changes)
@@ -675,7 +685,10 @@
newChildRev := childNode.Add(path, data, txid, makeBranch)
// Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
- childRev.SetName(name + "/" + keyValue.(string))
+ newChildRev.SetName(name + "/" + keyValue.(string))
+
+ branch.LatestLock.Lock()
+ defer branch.LatestLock.Unlock()
if idx >= 0 {
children[idx] = newChildRev
@@ -683,9 +696,6 @@
children = append(children, newChildRev)
}
- branch.LatestLock.Lock()
- defer branch.LatestLock.Unlock()
-
updatedRev := rev.UpdateChildren(name, children, branch)
n.makeLatest(branch, updatedRev, nil)
@@ -758,15 +768,15 @@
}
newChildRev := childNode.Remove(path, txid, makeBranch)
+ branch.LatestLock.Lock()
+ defer branch.LatestLock.Unlock()
+
if idx >= 0 {
children[idx] = newChildRev
} else {
children = append(children, newChildRev)
}
- branch.LatestLock.Lock()
- defer branch.LatestLock.Unlock()
-
rev.SetChildren(name, children)
branch.GetLatest().Drop(txid, false)
n.makeLatest(branch, rev, nil)
@@ -784,6 +794,7 @@
}
childRev.StorageDrop(txid, true)
+ GetRevCache().Cache.Delete(childRev.GetName())
branch.LatestLock.Lock()
defer branch.LatestLock.Unlock()