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  }