MCPcopy Create free account
hub / github.com/couchbase/sync_gateway / SimpleMultiChangesFeed

Method SimpleMultiChangesFeed

db/changes.go:709–1205  ·  view source on GitHub ↗

Returns the (ordered) union of all of the changes made to multiple channels.

(ctx context.Context, chans base.Set, options ChangesOptions)

Source from the content-addressed store, hash-verified

707
708// Returns the (ordered) union of all of the changes made to multiple channels.
709func (col *DatabaseCollectionWithUser) SimpleMultiChangesFeed(ctx context.Context, chans base.Set, options ChangesOptions) (<-chan *ChangeEntry, error) {
710
711 to := ""
712 if col.user != nil && col.user.Name() != "" {
713 to = fmt.Sprintf(" (to %s)", col.user.Name())
714 } else {
715 to = " (to ADMIN)"
716 }
717
718 base.InfofCtx(ctx, base.KeyChanges, "MultiChangesFeed(channels: %s, options: %s) ... %s", base.UD(chans), options, base.UD(to))
719 output := make(chan *ChangeEntry, 50)
720
721 collectionID := col.GetCollectionID()
722 go func() {
723
724 defer func() {
725 if panicked := recover(); panicked != nil {
726 base.WarnfCtx(ctx, "[%s] Unexpected panic sending changes - terminating changes: \n %s", panicked, debug.Stack())
727 } else {
728 base.InfofCtx(ctx, base.KeyChanges, "MultiChangesFeed done %s", base.UD(to))
729 }
730 close(output)
731 }()
732
733 var changeWaiter *ChangeWaiter
734 var lowSequence uint64
735 var currentCachedSequence uint64 // The highest contiguous sequence buffered over the caching feed
736 var lateSequenceFeeds map[channels.ID]*lateSequenceFeed
737 var useLateSequenceFeeds bool // LateSequence feeds are only used for continuous, or one-shot where options.RequestPlusSeq > currentCachedSequence
738 var userCounter uint64 // Wait counter used to identify changes to the user document
739 var changedChannels channels.ChangedKeys // Tracks channels added/removed to the user during changes processing.
740 var userChanged bool // Whether the user document has changed in a given iteration loop
741 var deferredBackfill bool // Whether there's a backfill identified in the user doc that's deferred while the SG cache catches up
742
743 // Retrieve the current max cached sequence - ensures there isn't a race between the subsequent channel cache queries
744 currentCachedSequence = col.changeCache().getChannelCache().GetHighCacheSequence()
745
746 // If changes feed requires more than one ChangesLoop iteration, initialize changeWaiter
747 if options.Wait || options.RequestPlusSeq > currentCachedSequence {
748 trackUnusedSequences := options.RequestPlusSeq > 0
749 changeWaiter = col.startChangeWaiter(trackUnusedSequences) // Waiter is updated with the actual channel set (post-user reload) at the start of the outer changes loop
750 userCounter = changeWaiter.CurrentUserCount()
751 // Reload user to pick up user changes that happened between auth and the change waiter
752 // initialization. Without this, notification for user doc changes in that window (a) won't be
753 // included in the initial changes loop iteration, and (b) won't wake up the ChangeWaiter.
754 if col.user != nil {
755 previousRoles := col.user.RoleNames()
756 if err := col.ReloadUser(ctx); err != nil {
757 base.WarnfCtx(ctx, "Error reloading user during changes initialization %q: %v", base.UD(col.user.Name()), err)
758 change := makeErrorEntry("User not found during reload - terminating changes feed")
759 output <- &change
760 return
761 }
762 changedRoles := col.user.RoleNames().CompareKeys(previousRoles)
763 if len(changedRoles) > 0 {
764 changeWaiter.RefreshUserKeys(col.User(), col.dbCtx.MetadataKeys)
765 }
766 }

Callers 1

MultiChangesFeedMethod · 0.95

Calls 15

startChangeWaiterMethod · 0.95
CurrentUserCountMethod · 0.95
ReloadUserMethod · 0.95
RefreshUserKeysMethod · 0.95
UserMethod · 0.95
closeLateFeedsMethod · 0.95
UpdateChannelsMethod · 0.95
getLateFeedMethod · 0.95
newLateSequenceFeedMethod · 0.95
changesFeedMethod · 0.95
appendUserFeedMethod · 0.95
buildRevokedFeedMethod · 0.95

Tested by

no test coverage detected