github.com/portworx/kvdb@v0.0.0-20241107215734-a185a966f535/updates_collector.go (about) 1 package kvdb 2 3 import ( 4 "fmt" 5 "strings" 6 "sync" 7 8 "github.com/sirupsen/logrus" 9 ) 10 11 type kvdbUpdate struct { 12 // prefix is the path on which update was triggered 13 prefix string 14 // kvp is the actual key-value pair update 15 kvp *KVPair 16 // errors on update 17 err error 18 } 19 20 type updatesCollectorImpl struct { 21 // stopped is true if collection is stopped 22 stopped bool 23 // stoppedMutex protects stopped flag 24 stoppedMutex sync.RWMutex 25 // start index 26 startIndex uint64 27 // updatesMutex protects updates and start index 28 updatesMutex sync.Mutex 29 // updates stores the updates in order 30 updates []*kvdbUpdate 31 } 32 33 func (c *updatesCollectorImpl) setStopped() { 34 c.stoppedMutex.Lock() 35 c.stopped = true 36 c.stoppedMutex.Unlock() 37 } 38 39 func (c *updatesCollectorImpl) isStopped() bool { 40 c.stoppedMutex.RLock() 41 defer c.stoppedMutex.RUnlock() 42 return c.stopped 43 } 44 45 func (c *updatesCollectorImpl) watchCb( 46 prefix string, 47 opaque interface{}, 48 kvp *KVPair, 49 err error, 50 ) error { 51 if c.isStopped() { 52 return fmt.Errorf("Stopped watch") 53 } 54 if err != nil { 55 c.setStopped() 56 return err 57 } 58 update := &kvdbUpdate{prefix: prefix, kvp: kvp, err: err} 59 c.updatesMutex.Lock() 60 c.updates = append(c.updates, update) 61 c.updatesMutex.Unlock() 62 return nil 63 } 64 65 func (c *updatesCollectorImpl) Stop() { 66 logrus.Info("Stopping updates collector") 67 c.setStopped() 68 } 69 70 func (c *updatesCollectorImpl) ReplayUpdates( 71 cbList []ReplayCb, 72 ) (uint64, error) { 73 c.updatesMutex.Lock() 74 updates := make([]*kvdbUpdate, len(c.updates)) 75 copy(updates, c.updates) 76 c.updatesMutex.Unlock() 77 index := c.startIndex 78 logrus.Infof("collect: replaying %d update(s) for %d callback(s)", 79 len(updates), len(cbList)) 80 for _, update := range updates { 81 if update.kvp == nil { 82 continue 83 } 84 index = update.kvp.ModifiedIndex 85 for _, cbInfo := range cbList { 86 if strings.HasPrefix(update.kvp.Key, cbInfo.Prefix) && 87 cbInfo.WaitIndex < update.kvp.ModifiedIndex { 88 err := cbInfo.WatchCB(update.prefix, cbInfo.Opaque, update.kvp, 89 update.err) 90 if err != nil { 91 logrus.Infof("collect error: watchCB returned error: %v", 92 err) 93 return index, err 94 } 95 } // else ignore the update 96 } 97 } 98 return index, nil 99 }