// Add the first change(s) from pendingLogs if they're the next sequence or have been waiting too // long, or if there are simply too many pending entries. // Returns the channels that changed. func (c *changeCache) _addPendingLogs() base.Set { var changedChannels base.Set for len(c.pendingLogs) > 0 { change := c.pendingLogs[0] isNext := change.Sequence == c.nextSequence if isNext || len(c.pendingLogs) > MaxChannelLogPendingCount || time.Since(c.pendingLogs[0].TimeReceived) >= MaxChannelLogPendingWaitTime { if !isNext { base.Warn("changeCache: Giving up, accepting #%d even though #%d is missing", change.Sequence, c.nextSequence) changeCacheExpvars.Add("outOfOrder", 1) } heap.Pop(&c.pendingLogs) changedChannels = changedChannels.Union(c._addToCache(change)) } else { break } } return changedChannels }
// Handles a newly-arrived LogEntry. func (c *changeCache) processEntry(change *LogEntry) base.Set { c.lock.Lock() defer c.lock.Unlock() if c.logsDisabled { return nil } sequence := change.Sequence nextSequence := c.nextSequence if _, found := c.receivedSeqs[sequence]; found { base.LogTo("Cache+", " Ignoring duplicate of #%d", sequence) return nil } c.receivedSeqs[sequence] = struct{}{} // FIX: c.receivedSeqs grows monotonically. Need a way to remove old sequences. var changedChannels base.Set if sequence == nextSequence || nextSequence == 0 { // This is the expected next sequence so we can add it now: changedChannels = c._addToCache(change) // Also add any pending sequences that are now contiguous: changedChannels = changedChannels.Union(c._addPendingLogs()) } else if sequence > nextSequence { // There's a missing sequence (or several), so put this one on ice until it arrives: heap.Push(&c.pendingLogs, change) numPending := len(c.pendingLogs) base.LogTo("Cache", " Deferring #%d (%d now waiting for #%d...#%d)", sequence, numPending, nextSequence, c.pendingLogs[0].Sequence-1) changeCacheExpvars.Get("maxPending").(*base.IntMax).SetIfMax(int64(numPending)) if numPending > MaxChannelLogPendingCount { // Too many pending; add the oldest one: changedChannels = c._addPendingLogs() } } else if sequence > c.initialSequence { // Out-of-order sequence received! base.Warn(" Received out-of-order change (seq %d, expecting %d) doc %q / %q", sequence, nextSequence, change.DocID, change.RevID) changedChannels = c._addToCache(change) } return changedChannels }