@@ -172,19 +172,7 @@ func (w *fileWatcher) processNotification(evt loginp.HarvesterStatus) {
172172func (w * fileWatcher ) watch (ctx unison.Canceler ) {
173173 w .log .Debug ("Start next scan" )
174174
175- << << << < HEAD
176175 paths := w .scanner .GetFiles ()
177- == == == =
178- // file identity is updated in GetFiles
179- now := time .Now ()
180- scanOpts := loginp.FileScanOptions {
181- CurrentTime : now ,
182- IgnoreOlder : ignoreOlder ,
183- IgnoreInactiveSince : ignoreInactiveSince ,
184- }
185- paths , scanMetrics := w .scanner .GetFiles (scanOpts )
186- metrics .UpdateFileScanMetrics (scanMetrics )
187- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
188176
189177 // for debugging purposes
190178 writtenCount := 0
@@ -207,8 +195,9 @@ func (w *fileWatcher) watch(ctx unison.Canceler) {
207195 continue
208196 }
209197
210- // srcID is the file identity (harvester ID/registry key), resolved lazily via ensureSrcID:
211- // an unchanged, untracked file (gzip, empty, ignore_older) never needs one, saving allocs.
198+ // srcID is the file identity (harvester ID/registry key), resolved lazily via
199+ // ensureSrcID: an unchanged file that produces no event never needs one, saving a
200+ // per-file identity allocation on every idle scan.
212201 var srcID string
213202 ensureSrcID := func () string {
214203 if srcID == "" { // getFileIdentity never returns ""
@@ -217,7 +206,8 @@ func (w *fileWatcher) watch(ctx unison.Canceler) {
217206 return srcID
218207 }
219208
220- // closedHarvesters is empty in the steady state; this reconciliation is usually skipped.
209+ // closedHarvesters is empty in the steady state, so this reconciliation is usually
210+ // skipped and the file identity is never resolved.
221211 if w .hasClosedHarvesters () {
222212 w .reconcileClosedHarvester (& prevDesc , ensureSrcID ())
223213 }
@@ -260,14 +250,6 @@ func (w *fileWatcher) watch(ctx unison.Canceler) {
260250 }
261251 }
262252
263- << << << < HEAD
264- == == == =
265- // Record progress metrics for trackable, non-truncated files (tracksHarvesterProgress).
266- if e .Op != loginp .OpTruncate && tracksHarvesterProgress (& fd , scanOpts ) {
267- harvesterFiles = append (harvesterFiles , loginp.HarvesterFile {ID : ensureSrcID (), Size : fd .Info .Size ()})
268- }
269-
270- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
271253 // delete from previous state to mark that we've seen the existing file again
272254 delete (w .prev , path )
273255 }
@@ -307,14 +289,6 @@ func (w *fileWatcher) watch(ctx unison.Canceler) {
307289 case w .events <- createEvent (path , * fd , w .getFileIdentity (* fd )):
308290 createdCount ++
309291 }
310- << << << < HEAD
311- == == == =
312-
313- // New files skip the main loop via early continue, so collect their metrics here.
314- if tracksHarvesterProgress (fd , scanOpts ) {
315- harvesterFiles = append (harvesterFiles , loginp.HarvesterFile {ID : srcID , Size : fd .Info .Size ()})
316- }
317- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
318292 }
319293
320294 w .log .Debugw ("File scan complete" ,
@@ -329,18 +303,27 @@ func (w *fileWatcher) watch(ctx unison.Canceler) {
329303 w .prev = paths
330304}
331305
332- << << << < HEAD
333- == == == =
334306// hasClosedHarvesters reports whether any harvester-close notification awaits reconciliation.
307+ // It is a cheap, lock-guarded length check so the watch loop can skip resolving a file identity
308+ // for every scanned file when there is nothing to reconcile (the common steady-state case).
335309func (w * fileWatcher ) hasClosedHarvesters () bool {
336310 w .closedHarvestersMutex .Lock ()
337311 defer w .closedHarvestersMutex .Unlock ()
338312 return len (w .closedHarvesters ) > 0
339313}
340314
341315// reconcileClosedHarvester folds a recently-closed harvester's ingested offset (from
342- // closedHarvesters) into prevDesc so a restarted harvester resumes from the right position.
343- // It guards a close-during-backoff race that would otherwise withhold writes and lose lines.
316+ // closedHarvesters) into prevDesc so a restarted harvester resumes from the right position,
317+ // then drops the entry.
318+ //
319+ // This prevents a race condition: when the reader/harvester reaches EOF it blocks on a backoff.
320+ // If during this time [logFile.shouldBeClosed] marks the file inactive and closes the reader
321+ // context, once the backoff expires the reader and harvester are closed without ingesting any
322+ // more data. If the fileWatcher sends a write event while the harvester was blocked, no new
323+ // harvester is started because one is already running, yet the fileWatcher updates its internal
324+ // state and won't send further write events until more data is added, so some lines can be
325+ // missed. By applying the offset reported when the harvester closed we realign our state and
326+ // start a new harvester if needed.
344327func (w * fileWatcher ) reconcileClosedHarvester (prevDesc * loginp.FileDescriptor , id string ) {
345328 w .closedHarvestersMutex .Lock ()
346329 defer w .closedHarvestersMutex .Unlock ()
@@ -353,30 +336,6 @@ func (w *fileWatcher) reconcileClosedHarvester(prevDesc *loginp.FileDescriptor,
353336 delete (w .closedHarvesters , id )
354337}
355338
356- // tracksHarvesterProgress reports whether a file contributes to the harvester progress metrics.
357- func tracksHarvesterProgress (fd * loginp.FileDescriptor , opts loginp.FileScanOptions ) bool {
358- return ! fd .GZIP && fd .Info .Size () > 0 && ! isFileIgnored (* fd , opts )
359- }
360-
361- // isFileIgnored returns true when a file is ignored, no matter the reason.
362- func isFileIgnored (
363- fd loginp.FileDescriptor ,
364- opts loginp.FileScanOptions ,
365- ) bool {
366- modTime := fd .Info .ModTime ()
367-
368- if opts .IgnoreOlder > 0 && opts .CurrentTime .Sub (modTime ) > opts .IgnoreOlder {
369- return true
370- }
371-
372- if ! opts .IgnoreInactiveSince .IsZero () && modTime .Sub (opts .IgnoreInactiveSince ) <= 0 {
373- return true
374- }
375-
376- return false
377- }
378-
379- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
380339// getFileIdentity mimics the same algorithm used by the harvester to generate
381340// the file identity to any given file.
382341// See 'startHarvester' on internal/input-logfile/harvester.go.
@@ -413,18 +372,8 @@ func (w *fileWatcher) Event() loginp.FSEvent {
413372 return <- w .events
414373}
415374
416- << << << < HEAD
417375func (w * fileWatcher ) GetFiles () map [string ]loginp.FileDescriptor {
418376 return w .scanner .GetFiles ()
419- == == == =
420- // GetFiles runs a one-off enumeration scan for the prospector's Init and
421- // TakeOver phases. Unlike the watch loop it does not advance the scanner's
422- // completedFingerprints set, so these pre-watch scans cannot suppress the
423- // bridging raw header a still-growing entry needs to migrate its registry key
424- // after a restart.
425- func (w * fileWatcher ) GetFiles (opts loginp .FileScanOptions ) (map [string ]loginp.FileDescriptor , loginp .FileScanMetrics ) {
426- return w .scanner .GetFiles (opts )
427- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
428377}
429378
430379type fingerprintConfig struct {
@@ -463,21 +412,11 @@ type fileScanner struct {
463412 hasher hash.Hash
464413 readBuffer []byte
465414 compression string
466- << << << < HEAD
467- == == == =
468- // completedFingerprints holds the paths whose fingerprint was already a
469- // final SHA-256 on the previous watch-loop scan (growing mode only). The
470- // bridging raw header is only useful on the scan a file crosses the
471- // threshold, so for paths in this set toFileDescriptor skips recomputing it.
472- // GetFiles itself is pure with respect to this set: only fileWatcher.watch
473- // advances it (after each scan), so the enumeration-only scans the
474- // prospector runs in Init/TakeOver cannot suppress the header a
475- // still-growing entry needs to migrate across a restart.
476- completedFingerprints map [string ]struct {}
477415
478416 // lastCount is the number of unique files the previous scan produced.
417+ // It pre-sizes the per-scan maps to avoid repeated grow/rehash allocations
418+ // on a stable file set.
479419 lastCount int
480- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
481420}
482421
483422func newFileScanner (logger * logp.Logger , paths []string , config fileScannerConfig , compression string ) (* fileScanner , error ) {
@@ -549,27 +488,13 @@ func (s *fileScanner) normalizeGlobPatterns() error {
549488
550489// GetFiles returns a map of file descriptors by filenames that
551490// match the configured paths.
552- << << << < HEAD
553491func (s * fileScanner ) GetFiles () map [string ]loginp.FileDescriptor {
554- fdByName := map [string ]loginp.FileDescriptor {}
555- == == == =
556- func (s * fileScanner ) GetFiles (opts loginp .FileScanOptions ) (map [string ]loginp.FileDescriptor , loginp .FileScanMetrics ) {
557- if opts .CurrentTime .IsZero () {
558- opts.CurrentTime = time .Now ()
559- }
560-
561- // Pre-size the per-scan maps from the previous scan's count.
492+ // Pre-size the per-scan maps from the previous scan's unique-file count.
562493 fdByName := make (map [string ]loginp.FileDescriptor , s .lastCount )
563- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
564494 // used to determine if a symlink resolves in a already known target
565495 uniqueIDs := make (map [string ]string , s .lastCount )
566496 // used to filter out duplicate matches
567- << << << < HEAD
568- uniqueFiles := map [string ]struct {}{}
569- == == == =
570497 uniqueFiles := make (map [string ]struct {}, s .lastCount )
571- scanMetrics := loginp.FileScanMetrics {}
572- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
573498
574499 for _ , path := range s .paths {
575500 matches , err := filepath .Glob (path )
@@ -621,13 +546,8 @@ func (s *fileScanner) GetFiles(opts loginp.FileScanOptions) (map[string]loginp.F
621546 }
622547 }
623548
624- << << << < HEAD
625- return fdByName
626- == == == =
627- scanMetrics .FilesUnique = int64 (len (fdByName ))
628549 s .lastCount = len (fdByName )
629- return fdByName , scanMetrics
630- >> >> >> > c05890c43 (filestream : reduce per - scan allocations (#51863 ))
550+ return fdByName
631551}
632552
633553type ingestTarget struct {
0 commit comments