Skip to content

in_tail: Serialize DB operation for preventing resource collisions on threaded mode - #11460

Merged
edsiper merged 2 commits into
masterfrom
cosmo0920-serialize-db-operation-on-on_tail
Feb 13, 2026
Merged

in_tail: Serialize DB operation for preventing resource collisions on threaded mode#11460
edsiper merged 2 commits into
masterfrom
cosmo0920-serialize-db-operation-on-on_tail

Conversation

@cosmo0920

@cosmo0920 cosmo0920 commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

Closes #11357.


Enter [N/A] in the box, if an item is not applicable to your change.

Testing
Before we can approve your change; please submit the following in a comment:

  • Example configuration file for the change
[SERVICE]
    Log_Level debug
    Flush 1
    Daemon Off
    # Parsers_File parsers.conf

[INPUT]
    Name tail
    Tag access
    Path access.log
    Path_Key filepath
    Key data
    Read_from_Head true
    DB file-access.db
    DB.locking true
    Refresh_Interval 10
    Threaded true

[OUTPUT]
    Name stdout
    Match *

[OUTPUT]
    Name file
    Match access
    Path ./output/
    File access.log
    Mkdir True

On another terminal before launching fluent-bit:

$ echo "line1" > access.log; echo "line2" >> access.log; echo "line3" >> access.log

after fluent-bit launched:

$ echo "line4" >> access.log; mv access.log access.log.1; echo "line5" > access.log

There's no duplicated lines:

% cat output/access.log
access: [1770973676.233236000, {"filepath":"access.log","data":"line1"}]
access: [1770973676.233240000, {"filepath":"access.log","data":"line2"}]
access: [1770973676.233240000, {"filepath":"access.log","data":"line3"}]
access: [1770973705.990725000, {"filepath":"access.log","data":"line4"}]
access: [1770973706.238184000, {"filepath":"access.log","data":"line5"}]
  • Debug log output from testing the change
Fluent Bit v5.0.0
* Copyright (C) 2015-2025 The Fluent Bit Authors
* Fluent Bit is a CNCF graduated project under the Fluent organization
* https://fluentbit.io

______ _                  _    ______ _ _           _____  _____           _            
|  ___| |                | |   | ___ (_) |         |  ___||  _  |         | |           
| |_  | |_   _  ___ _ __ | |_  | |_/ /_| |_  __   _|___ \ | |/' |______ __| | _____   __
|  _| | | | | |/ _ \ '_ \| __| | ___ \ | __| \ \ / /   \ \|  /| |______/ _` |/ _ \ \ / /
| |   | | |_| |  __/ | | | |_  | |_/ / | |_   \ V //\__/ /\ |_/ /     | (_| |  __/\ V / 
\_|   |_|\__,_|\___|_| |_|\__| \____/|_|\__|   \_/ \____(_)\___/       \__,_|\___| \_/


[2026/02/13 18:07:56.229900000] [ info] Configuration:
[2026/02/13 18:07:56.229910000] [ info]  flush time     | 1.000000 seconds
[2026/02/13 18:07:56.229917000] [ info]  grace          | 5 seconds
[2026/02/13 18:07:56.229924000] [ info]  daemon         | 0
[2026/02/13 18:07:56.229929000] [ info] ___________
[2026/02/13 18:07:56.229934000] [ info]  inputs:
[2026/02/13 18:07:56.229938000] [ info]      tail
[2026/02/13 18:07:56.229943000] [ info] ___________
[2026/02/13 18:07:56.229947000] [ info]  filters:
[2026/02/13 18:07:56.229952000] [ info] ___________
[2026/02/13 18:07:56.229956000] [ info]  outputs:
[2026/02/13 18:07:56.229960000] [ info]      stdout.0
[2026/02/13 18:07:56.229965000] [ info]      file.1
[2026/02/13 18:07:56.229969000] [ info] ___________
[2026/02/13 18:07:56.229976000] [ info]  collectors:
[2026/02/13 18:07:56.230140000] [ info] [fluent bit] version=5.0.0, commit=5857b7dfe8, pid=6313
[2026/02/13 18:07:56.230149000] [debug] [engine] coroutine stack size: 36864 bytes (36.0K)
[2026/02/13 18:07:56.230204000] [ info] [storage] ver=1.5.4, type=memory, sync=normal, checksum=off, max_chunks_up=128
[2026/02/13 18:07:56.230219000] [ info] [simd    ] NEON
[2026/02/13 18:07:56.230223000] [ info] [cmetrics] version=1.0.7
[2026/02/13 18:07:56.230249000] [ info] [ctraces ] version=0.7.0
[2026/02/13 18:07:56.230341000] [ info] [input:tail:tail.0] initializing
[2026/02/13 18:07:56.230345000] [ info] [input:tail:tail.0] storage_strategy='memory' (memory only)
[2026/02/13 18:07:56.232637000] [debug] [input:tail:tail.0] flb_tail_fs_stat_init() initializing stat tail input
[2026/02/13 18:07:56.232647000] [debug] [input:tail:tail.0] scanning path access.log
[2026/02/13 18:07:56.232706000] [debug] [input:tail:tail.0] db file set called for access.log inode=88672876
[2026/02/13 18:07:56.232908000] [debug] [input:tail:tail.0] inode=88672876 with offset=0 appended as access.log
[2026/02/13 18:07:56.232913000] [debug] [input:tail:tail.0] scan_glob add(): access.log, inode 88672876
[2026/02/13 18:07:56.232917000] [debug] [input:tail:tail.0] 1 new files found on path 'access.log'
[2026/02/13 18:07:56.232945000] [ info] [input:tail:tail.0] db: delete unmonitored stale inodes from the database: count=0
[2026/02/13 18:07:56.232951000] [debug] [input:tail:tail.0] [thread init] initialization OK
[2026/02/13 18:07:56.232959000] [ info] [input:tail:tail.0] thread instance initialized
[2026/02/13 18:07:56.232967000] [debug] [tail:tail.0] created event channels: read=45 write=46
[2026/02/13 18:07:56.232976000] [debug] [stdout:stdout.0] created event channels: read=49 write=50
[2026/02/13 18:07:56.233038000] [debug] [file:file.1] created event channels: read=58 write=59
[2026/02/13 18:07:56.233074000] [ info] [output:stdout:stdout.0] worker #0 started
[2026/02/13 18:07:56.233114000] [debug] [router] match rule tail.0:stdout.0
[2026/02/13 18:07:56.233119000] [debug] [router] match rule tail.0:file.1
[2026/02/13 18:07:56.233118000] [ info] [output:file:file.1] worker #0 started
[2026/02/13 18:07:56.233163000] [ info] [sp] stream processor started
[2026/02/13 18:07:56.233204000] [ info] [engine] Shutdown Grace Period=5, Shutdown Input Grace Period=2
[2026/02/13 18:07:56.233300000] [debug] [input:tail:tail.0] [static files] processed 18b
[2026/02/13 18:07:56.233308000] [debug] [input:tail:tail.0] inode=88672876 file=access.log promote to TAIL_EVENT
[2026/02/13 18:07:56.233320000] [debug] [input:tail:tail.0] [static files] processed 0b, done
[2026/02/13 18:07:57.236570000] [debug] [task] created task=0x6000037b4000 id=0 OK
[2026/02/13 18:07:57.236673000] [debug] [output:stdout:stdout.0] task_id=0 assigned to thread #0
[2026/02/13 18:07:57.236760000] [debug] [output:file:file.1] task_id=0 assigned to thread #0
[0] access: [[1770973676.233236000, {}], {"filepath"=>"access.log", "data"=>"line1"}]
[1] access: [[1770973676.233240000, {}], {"filepath"=>"access.log", "data"=>"line2"}]
[2] access: [[1770973676.233240000, {}], {"filepath"=>"access.log", "data"=>"line3"}]
[2026/02/13 18:07:57.237305000] [debug] [output:file:file.1] creating directory ./output
[2026/02/13 18:07:57.237433000] [debug] [out flush] cb_destroy coro_id=0
[2026/02/13 18:07:57.239142000] [debug] [out flush] cb_destroy coro_id=0
[2026/02/13 18:07:57.239280000] [debug] [task] destroy task=0x6000037b4000 (task_id=0)
[2026/02/13 18:08:06.236668000] [debug] [input:tail:tail.0] scanning path access.log
[2026/02/13 18:08:06.236734000] [debug] [input:tail:tail.0] scan_blog add(): dismissed: access.log, inode 88672876
[2026/02/13 18:08:06.236746000] [debug] [input:tail:tail.0] 0 new files found on path 'access.log'
[2026/02/13 18:08:16.236506000] [debug] [input:tail:tail.0] scanning path access.log
[2026/02/13 18:08:16.236528000] [debug] [input:tail:tail.0] scan_blog add(): dismissed: access.log, inode 88672876
[2026/02/13 18:08:16.236533000] [debug] [input:tail:tail.0] 0 new files found on path 'access.log'
[2026/02/13 18:08:26.236736000] [debug] [input:tail:tail.0] inode=88672876 rotated: access.log => /Users/hiroshihatake/GitHub/fluent-bit/build/access.log.1
[2026/02/13 18:08:26.236821000] [debug] [input:tail:tail.0] inode=88672876 rotated access.log -> /Users/hiroshihatake/GitHub/fluent-bit/build/access.log.1
[2026/02/13 18:08:26.236936000] [debug] [task] created task=0x6000037a8000 id=0 OK
[2026/02/13 18:08:26.236891000] [ info] [input:tail:tail.0] inode=88672876 handle rotation(): access.log => /Users/hiroshihatake/GitHub/fluent-bit/build/access.log.1
[2026/02/13 18:08:26.236985000] [debug] [output:stdout:stdout.0] task_id=0 assigned to thread #0
[2026/02/13 18:08:26.237020000] [debug] [output:file:file.1] task_id=0 assigned to thread #0
[0] access: [[1770973705.990725000, {}], {"filepath"=>"access.log", "data"=>"line4"}]
[2026/02/13 18:08:26.237351000] [debug] [out flush] cb_destroy coro_id=1
[2026/02/13 18:08:26.237718000] [debug] [input:tail:tail.0] db file set called for access.log inode=88673054
[2026/02/13 18:08:26.238015000] [debug] [input:tail:tail.0] inode=88673054 with offset=0 appended as access.log
[2026/02/13 18:08:26.238064000] [debug] [input:tail:tail.0] scanning path access.log
[2026/02/13 18:08:26.238119000] [debug] [input:tail:tail.0] scan_blog add(): dismissed: access.log, inode 88673054
[2026/02/13 18:08:26.238134000] [debug] [out flush] cb_destroy coro_id=1
[2026/02/13 18:08:26.238139000] [debug] [input:tail:tail.0] 0 new files found on path 'access.log'
[2026/02/13 18:08:26.238222000] [debug] [task] destroy task=0x6000037a8000 (task_id=0)
[2026/02/13 18:08:26.238652000] [debug] [input:tail:tail.0] [static files] processed 6b
[2026/02/13 18:08:26.238775000] [debug] [input:tail:tail.0] inode=88673054 file=access.log promote to TAIL_EVENT
[2026/02/13 18:08:26.238928000] [debug] [input:tail:tail.0] [static files] processed 0b, done
[2026/02/13 18:08:27.238113000] [debug] [task] created task=0x6000037a8000 id=0 OK
[2026/02/13 18:08:27.238206000] [debug] [output:stdout:stdout.0] task_id=0 assigned to thread #0
[0] access: [[1770973706.238184000, {}], {"filepath"=>"access.log", "data"=>"line5"}]
[2026/02/13 18:08:27.238292000] [debug] [output:file:file.1] task_id=0 assigned to thread #0
[2026/02/13 18:08:27.238485000] [debug] [out flush] cb_destroy coro_id=2
[2026/02/13 18:08:27.239346000] [debug] [out flush] cb_destroy coro_id=2
[2026/02/13 18:08:27.239514000] [debug] [task] destroy task=0x6000037a8000 (task_id=0)
[2026/02/13 18:08:31.236829000] [debug] [input:tail:tail.0] inode=88672876 purge rotated file /Users/hiroshihatake/GitHub/fluent-bit/build/access.log.1 (offset=24 / size = 24)
[2026/02/13 18:08:31.236912000] [debug] [input:tail:tail.0] inode=88672876 removing file name /Users/hiroshihatake/GitHub/fluent-bit/build/access.log.1
[2026/02/13 18:08:31.237333000] [debug] [input:tail:tail.0] db: file deleted from database: /Users/hiroshihatake/GitHub/fluent-bit/build/access.log.1
^C[2026/02/13 18:08:34] [engine] caught signal (SIGINT)
[2026/02/13 18:08:34.81773000] [debug] [input:tail:tail.0] thread pause instance
[2026/02/13 18:08:34.81836000] [ info] [output:stdout:stdout.0] thread worker #0 stopping...
[2026/02/13 18:08:34.81946000] [ info] [output:stdout:stdout.0] thread worker #0 stopped
[2026/02/13 18:08:34.82048000] [ info] [output:file:file.1] thread worker #0 stopping...
[2026/02/13 18:08:34.82152000] [ info] [output:file:file.1] thread worker #0 stopped
[2026/02/13 18:08:34.82257000] [debug] [input:tail:tail.0] inode=88673054 removing file name access.log
[2026/02/13 18:08:34.83517000] [debug] [input:tail:tail.0] thread exit instance
  • Attached Valgrind output that shows no leaks or memory corruption was found

If this is a change to packaging of containers or native binaries then please confirm it works for all targets.

  • Run local packaging test showing all targets (including any new ones) build.
  • Set ok-package-test label to test for all targets (requires maintainer to do).

Documentation

  • Documentation required for this feature

Backporting

  • Backport to latest stable release.

Fluent Bit is licensed under Apache 2.0, by submitting this pull request I understand that this code will be released under the terms of that license.

Summary by CodeRabbit

  • Bug Fixes
    • Added synchronization around database operations to prevent concurrent access conflicts and improve data integrity; locks now released on all success and error paths to avoid deadlocks.
    • Added debug logging for database operations to aid troubleshooting and visibility.
    • Extended lock retry logic to treat an additional transient error as retryable, improving robustness of lock acquisition.

@coderabbitai

coderabbitai Bot commented Feb 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds DB lock/unlock helpers and wraps tail plugin database operations (open, file set, offset, rotate, delete, stale-file delete) with explicit locking and unlock-on-error; updates flb_tail_db_open signature to accept ctx and inserts debug logs for DB-targeted file/inode operations.

Changes

Cohort / File(s) Summary
Tail DB locking & ops
plugins/in_tail/tail_db.c
Add tail_db_lock/tail_db_unlock helpers; change flb_tail_db_open signature to include ctx; acquire/release DB lock around flb_tail_db_file_set, flb_tail_db_file_offset, flb_tail_db_file_rotate, flb_tail_db_file_delete, flb_tail_db_stale_file_delete; add debug logs and ensure unlock on all error paths.
Lock retry behavior
src/flb_lock.c
Treat EBUSY as transient in flb_lock_acquire retry logic (alongside EAGAIN), causing additional retry attempts before failing.

Sequence Diagram(s)

sequenceDiagram
    participant Tail as Tail Worker
    participant Lock as DB Lock (tail_db_lock / tail_db_unlock)
    participant DB as SQLite DB

    Tail->>Lock: request lock (tail_db_lock)
    Lock-->>Tail: lock acquired
    Tail->>DB: perform DB operation (open/set/offset/rotate/delete)
    DB-->>Tail: operation result (ok / error)
    Tail->>Lock: release lock (tail_db_unlock)
    Lock-->>Tail: lock released
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Suggested labels

backport to v4.0.x

Suggested reviewers

  • edsiper
  • koleini
  • fujimotos

Poem

🐇 I nibble bytes and guard the rows,
I clutch the lock where sqlite grows,
No skipped offsets, no tangled thread,
I hop, unlock, and keep logs fed,
Tiny paws, big syncs — onward we go! 🥕

🚥 Pre-merge checks | ✅ 5 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: adding serialization of database operations in in_tail to prevent resource collisions in threaded mode, which directly addresses the linked issue #11357.
Linked Issues check ✅ Passed The changes implement serialization via inline locking helpers (tail_db_lock/tail_db_unlock) and add locking around all DB operations, directly addressing issue #11357's requirement to maintain file position tracking and prevent re-reading in threaded mode.
Out of Scope Changes check ✅ Passed All changes are scoped to addressing the linked issue: DB operation serialization in in_tail plugin and EBUSY error handling in flb_lock are both necessary for fixing threaded mode file position tracking.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into master

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cosmo0920-serialize-db-operation-on-on_tail

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
src/flb_lock.c (1)

76-93: Consider: flb_lock_release retry on EAGAIN may be dead code for non-recursive mutexes.

pthread_mutex_unlock doesn't return EAGAIN or EBUSY for default (non-recursive) mutexes — it returns EPERM on ownership errors. The retry loop here would never actually retry; any error would hit the break. This is pre-existing and not introduced by this PR, but worth noting if this code is being actively maintained.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
@cosmo0920
cosmo0920 force-pushed the cosmo0920-serialize-db-operation-on-on_tail branch from c2e82e0 to eeba913 Compare February 13, 2026 09:16

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c2e82e062c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/in_tail/tail_db.c
Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
@cosmo0920 cosmo0920 added this to the Fluent Bit v5.0 milestone Feb 13, 2026
@edsiper
edsiper merged commit e44c639 into master Feb 13, 2026
57 of 60 checks passed
@edsiper
edsiper deleted the cosmo0920-serialize-db-operation-on-on_tail branch February 13, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Threaded mode always re-reads files from beginning regardless of DB offset or Read_from_Head setting

2 participants