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

Method processEntry

db/change_cache.go:755–833  ·  view source on GitHub ↗

processEntry handles a newly-arrived LogEntry and returns the changes channels from this revision. This can be any existing, removed or newly added channels. Its possible for channels slice returned to have duplicates in it. It is the callers responsibility to de-duplicate before notifying any chang

(ctx context.Context, change *LogEntry)

Source from the content-addressed store, hash-verified

753// This can be any existing, removed or newly added channels. Its possible for channels slice returned to have duplicates
754// in it. It is the callers responsibility to de-duplicate before notifying any changes.
755func (c *changeCache) processEntry(ctx context.Context, change *LogEntry) []channels.ID {
756 c.lock.Lock()
757 defer c.lock.Unlock()
758 if c.logsDisabled {
759 return nil
760 }
761
762 sequence := change.Sequence
763 if change.Sequence > c.internalStats.highSeqFeed {
764 c.internalStats.highSeqFeed = change.Sequence
765 }
766
767 // Duplicate handling - there are a few cases where processEntry can be called multiple times for a sequence:
768 // - recentSequences for rapidly updated documents
769 // - principal mutations that don't increment sequence
770 // We can cancel processing early in these scenarios.
771 // Check if this is a duplicate of an already processed sequence
772 if sequence < c.nextSequence && !change.Skipped {
773 // check for presence in skippedSeqs, it's possible that change.skipped can be marked false in recent sequence handling
774 // but this change is subsequently pushed to skipped before acquiring cache mutex in this function
775 if !c.WasSkipped(sequence) {
776 base.DebugfCtx(ctx, base.KeyCache, " Ignoring duplicate of #%d", sequence)
777 return nil
778 } else {
779 change.Skipped = true
780 }
781 }
782
783 // Check if this is a duplicate of a pending sequence
784 if _, found := c.receivedSeqs[sequence]; found {
785 base.DebugfCtx(ctx, base.KeyCache, " Ignoring duplicate of #%d", sequence)
786 return nil
787 }
788 c.receivedSeqs[sequence] = struct{}{}
789
790 changedChannels := make([]channels.ID, 0, len(change.Channels))
791 if sequence == c.nextSequence || c.nextSequence == 0 {
792 // This is the expected next sequence so we can add it now:
793 changedChannels = c._addToCache(ctx, change)
794 // Also add any pending sequences that are now contiguous:
795 changedChannels = append(changedChannels, c._addPendingLogs(ctx)...)
796 } else if sequence > c.nextSequence {
797 // There's a missing sequence (or several), so put this one on ice until it arrives:
798 heap.Push(&c.pendingLogs, change)
799 numPending := len(c.pendingLogs)
800 c.internalStats.pendingSeqLen = numPending
801 if base.LogDebugEnabled(ctx, base.KeyCache) {
802 base.DebugfCtx(ctx, base.KeyCache, " Deferring #%d (%d now waiting for #%d...#%d) doc %q / %q",
803 sequence, numPending, c.nextSequence, c.pendingLogs[0].Sequence-1, base.UD(change.DocID), change.RevID)
804 }
805 // Update max pending high watermark stat
806 if numPending > c.internalStats.maxPending {
807 c.internalStats.maxPending = numPending
808 }
809
810 if numPending > c.options.CachePendingSeqMaxNum {
811 // Too many pending; add the oldest one:
812 changedChannels = append(changedChannels, c._addPendingLogs(ctx)...)

Calls 10

WasSkippedMethod · 0.95
_addToCacheMethod · 0.95
_addPendingLogsMethod · 0.95
RemoveSkippedMethod · 0.95
DebugfCtxFunction · 0.92
LogDebugEnabledFunction · 0.92
UDFunction · 0.92
PushMethod · 0.80
LockMethod · 0.45
UnlockMethod · 0.45