Bug 13181 - persist_data sqlite database mixed with forking is irreparably broken
Summary: persist_data sqlite database mixed with forking is irreparably broken
Status: NEW
Alias: None
Product: BitBake
Classification: Build System, Metadata & Runtime
Component: bitbake (show other bugs)
Version: unspecified
Hardware: x86 Multiple
: Medium+ normal
Target Milestone: 6.1 M1
Assignee: Unassigned
QA Contact:
URL:
Whiteboard:
Depends on:
Blocks:
 
Reported: 2019-02-14 19:11 UTC by Joshua Watt
Modified: 2026-03-18 21:43 UTC (History)
6 users (show)

See Also:
OS type for building Yocto: ---
Type of Regression: ---
Verified:
Documentation change: No (bug/feature does not impact docs)


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Joshua Watt 2019-02-14 19:11:25 UTC
The current persist_data uses a sqlite database that is shared among all the threads that wish to access it. The bitbake worker processes that spawn off are forked off of other processes which are also accessing the database, which causes the underlying sqlite database object to be cloned into the new child process. Once this is done, the game is over however because while the python sqlite state and underlying file descriptor are copied to the new process, the POSIX advisory locks that it had aren't. This means that there is essential no record to any other process that the new child exists and needs to be synchronized with other sqlite connections. This can cause all sorts of synchronization problems since the database pages might get flushed, or even worse unmapped from memory while the "hidden" child process is trying to read from it (this is the specific case I found; the child processes were dying with a SIGBUS error in sqlite).

sqlite admits this is a problem a little more succinctly and recommends that if you *must* carry an open connection across a fork(), you immediately close() (not sqlite3_close()!) the underlying file descriptor: https://www.sqlite.org/howtocorrupt.html#_carrying_an_open_database_connection_across_a_fork_ . However, python being what it is, this isn't a very tenable solution since 
1) we don't have direct access to the underlying file descriptor
2) couldn't prevent python from garbage collecting the sqlite database object
3) The os.register_at_fork() API wasn't added until Python 3.7
4) Even if the os.register_at_fork() handler was available, it's a pretty ugly hack.

Note that this problem probably isn't biting us at all currently because of the read-only and single process nature of the persist_data; that is data is mostly only read and only done so by a single process, but this is likely to change with https://bugzilla.yoctoproject.org/show_bug.cgi?id=13030 .

I believe that the best long term solution is to rework persist data to use a client server model where a single server process handles the sqlite database and manages requests on behalf of the clients.

I've started incubating a python module that can do such a thing efficiently for  read-mostly uses cases using shared memory here: https://github.com/JPEWdev/pyradur
Comment 1 Randy MacLeod 2023-07-26 21:21:59 UTC
Bulk move of 64 bugs to 4.3 M3 after a quick review.
If a bug is actually fixed, please add a commit link and resolve it.
-- Randy for YP bug team.
Comment 2 Trevor Gamblin 2023-09-14 15:56:01 UTC
Moved to M4.
Comment 3 Randy MacLeod 2023-10-30 15:29:07 UTC
Bulk move to 5.0 M1. -- Randy
Comment 4 Randy MacLeod 2023-12-21 23:28:25 UTC
Bulk move of 52 5.0-M1 bugs to M2.
Comment 5 Randy MacLeod 2024-01-25 14:28:44 UTC
Bulk move of bugs owned by "unassigned" from 5.0-M2 to 5.0-M3.
Comment 6 Randy MacLeod 2024-02-22 19:53:22 UTC
Bulk move of bugs from 5.0-M3 to 5.99.
The bugs in this list are all unassigned and are ones that I consider to be nice to do some time but not essential track from milestone to milestone in 5.0 or 5.1. We agreed on this bug handling approach in the YP bug review on Feb 22, 2024.

If you disagree, please move back to a 5.[012...]-M* milestone.
Comment 7 Randy MacLeod 2026-03-18 21:43:06 UTC
Optimistically moving to 6.1-M1, albeit as unassigned.