go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/internal/graph/graph_impl.go (about) 1 // Copyright (c) 2018 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package graph 16 17 import ( 18 "sync" 19 "time" 20 ) 21 22 const ( 23 // how often (at most) the log of previous revisions gets trimmed to remove 24 // records too old to keep 25 oldRevsTrimmingPeriod = 1 * time.Minute 26 ) 27 28 // kvgraph implements Graph interface. 29 type kvgraph struct { 30 rwLock sync.RWMutex 31 graph *graphR 32 33 startTime time.Time 34 lastRevTrimming time.Time // last time the history of revisions was trimmed 35 recordOldRevs bool 36 recordAgeLimit time.Duration 37 permanentInitPeriod time.Duration 38 39 methodTracker MethodTracker 40 } 41 42 // MethodTracker can be optionally supplied to track beginning and end of calls 43 // for (non-trivial) graph methods. 44 type MethodTracker func(method string) (onReturn func()) 45 46 // Opts groups input options for the graph constructor. 47 type Opts struct { 48 RecordOldRevs bool 49 RecordAgeLimit uint32 50 PermanentInitPeriod uint32 51 52 MethodTracker MethodTracker 53 } 54 55 // NewGraph creates and new instance of key-value graph. 56 // <recordOldRevs> if enabled, will cause the graph to record the previous 57 // revisions of every node that have ever existed. <recordAgeLimit> is in minutes 58 // and allows to limit the maximum age of a record to keep, avoiding infinite 59 // memory usage growth. The initial phase of the execution is, however, of greater 60 // significance and <permanentInitPeriod> allows to keep records from that period 61 // permanently in memory. 62 func NewGraph(opts Opts) Graph { 63 kvgraph := &kvgraph{ 64 startTime: time.Now(), 65 lastRevTrimming: time.Now(), 66 recordOldRevs: opts.RecordOldRevs, 67 recordAgeLimit: time.Duration(opts.RecordAgeLimit) * time.Minute, 68 permanentInitPeriod: time.Duration(opts.PermanentInitPeriod) * time.Minute, 69 methodTracker: opts.MethodTracker, 70 } 71 kvgraph.graph = newGraphR(opts.MethodTracker) 72 kvgraph.graph.parent = kvgraph 73 return kvgraph 74 } 75 76 // Read returns a graph handle for read-only access. 77 // The graph supports multiple concurrent readers. 78 // Release eventually using Release() method. 79 func (kvgraph *kvgraph) Read() ReadAccess { 80 kvgraph.rwLock.RLock() 81 return kvgraph.graph 82 } 83 84 // Write returns a graph handle for read-write access. 85 // The graph supports at most one writer at a time - i.e. it is assumed 86 // there is no write-concurrency. 87 // If <inPlace> is enabled, the changes are applied with immediate effect, 88 // otherwise they are propagated to the graph using Save(). 89 // In-place Write handle holds write lock, therefore reading is blocked until 90 // the handle is released. 91 // If <record> is true, the changes will be recorded once the handle is 92 // released. 93 // Release eventually using Release() method. 94 func (kvgraph *kvgraph) Write(inPlace, record bool) RWAccess { 95 if kvgraph.methodTracker != nil { 96 defer kvgraph.methodTracker("Write")() 97 } 98 if inPlace { 99 kvgraph.rwLock.Lock() 100 } 101 return newGraphRW(kvgraph.graph, inPlace, record) 102 }