Wrap package creation's stub database inserts in a single transaction - #195
Conversation
mport_create_primative wrote the bundle's stub database one autocommit INSERT at a time, so SQLite synced the journal to disk for every asset row. A port with thousands of files paid one fsync per file, which dominated the wall-clock time of mport.create on slower storage. Open a transaction after the stub schema is created, commit it after the last insert, and roll back and close the handle on any failure. The stub database is rebuilt from scratch on every run and discarded on error, so there is no durability requirement between rows. The rollback goes through sqlite3_exec directly so it cannot clobber the error being returned. The failure path now also closes the stub handle, which was previously leaked. Creating a 4000-file package on ZFS drops from about 27 seconds to under one second. Fixes #193 AI-Assisted-By: Claude Fable 5.1 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VqVYKWFCX58Cb5NiGHHjzo
Reviewer's GuidePackage creation now performs all stub database inserts in a single transaction, substantially reducing bulk-build overhead while ensuring failures roll back, close the database handle, and remove temporary state without clobbering the original error. Sequence diagram for transactional package creationsequenceDiagram
participant Creator as mport_create_primative
participant DB as StubDatabase
participant FS as TemporaryState
Creator->>DB: create_stub_db()
Creator->>DB: mport_db_do(BEGIN TRANSACTION)
Creator->>DB: insert_assetlist()
Creator->>DB: insert_meta()
Creator->>DB: mport_db_do(COMMIT TRANSACTION)
Creator->>DB: sqlite3_close()
Creator->>FS: clean_up(tmpdir)
alt insert or transaction failure
Creator->>DB: sqlite3_exec(ROLLBACK)
Creator->>DB: sqlite3_close()
Creator->>FS: clean_up(tmpdir)
end
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Claude finished @laffer1's task in 2m 17s —— View job Claude finished the code review
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="libmport/create_primative.c" line_range="128-133" />
<code_context>
+ return error_code;
+
+DBFAIL:
+ /* sqlite3_exec directly so the rollback cannot clobber the error; a no-op if
+ * the transaction never began or was already committed */
+ (void)sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
+ (void)sqlite3_close(db);
+ clean_up(tmpdir);
+
return error_code;
</code_context>
<issue_to_address>
**issue (bug_risk):** When an insert fails after preparing a SQLite statement, several insert helpers return without finalizing that statement; the DBFAIL cleanup then ignores SQLITE_BUSY from sqlite3_close, leaving the stub handle open while the temporary directory is removed.
**Triggers:** When an asset bind/step fails or malformed dependency data causes an early return from an insert helper.
**Suggested fix:** Ensure every insert helper finalizes its statement on all error paths before DBFAIL calls sqlite3_close, and check or otherwise handle the close result.
</issue_to_address>…schema failure Review of #195 pointed out two gaps around the new DBFAIL rollback path. Several insert helpers returned from a bind or step failure without finalizing their prepared statement, so sqlite3_close in DBFAIL could return SQLITE_BUSY and leave the stub handle open. And when mport_generate_stub_schema failed, create_stub_db returned with the connection still open and the caller never closed it. Route every failure in insert_assetlist, insert_meta and insert_depends through a single label that finalizes the statement, finalize before the regcomp failure return in insert_conflicts, and close the handle in create_stub_db when schema creation fails. insert_meta also no longer leaks os_release on bind failures. Error codes and messages are unchanged. Verified by forcing a malformed depend through mport.create: it exits 1 with the original message, produces no bundle, and leaves no temp dir. AI-Assisted-By: Claude Fable 5.1 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VqVYKWFCX58Cb5NiGHHjzo
|
Claude finished @laffer1's task in 1m 20s —— View job Re-review of
|
…schema failure Review of #195 pointed out two gaps around the new DBFAIL rollback path. Several insert helpers returned from a bind or step failure without finalizing their prepared statement, so sqlite3_close in DBFAIL could return SQLITE_BUSY and leave the stub handle open. And when mport_generate_stub_schema failed, create_stub_db returned with the connection still open and the caller never closed it. Route every failure in insert_assetlist, insert_meta and insert_depends through a single label that finalizes the statement, finalize before the regcomp failure return in insert_conflicts, and close the handle in create_stub_db when schema creation fails. insert_meta also no longer leaks os_release on bind failures. Error codes and messages are unchanged. Verified by forcing a malformed depend through mport.create: it exits 1 with the original message, produces no bundle, and leaves no temp dir. AI-Assisted-By: Claude Fable 5.1 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VqVYKWFCX58Cb5NiGHHjzo Signed-off-by: Lucas Holt <luke@foolishgames.com>

Fixes #193.
Summary
mport_create_primativenow opens a transaction after the stub schema is created, runs the asset, package, depends, conflicts, categories and annotation inserts, and commits before closing the handle.DBFAILlabel that rolls back viasqlite3_exec(so the original error is not clobbered), closes the handle, and removes the temp directory. This matches the rollback pattern in the delete and install paths.Verification
libmportandmport.createbuild clean under-Werror.kyua test mport_create_test: 5/5 passed.Timing
mport.createon a 4000-file staged tree, three runs each, ZFS/tmp:🤖 Generated with Claude Code
https://claude.ai/code/session_01VqVYKWFCX58Cb5NiGHHjzo
Summary by Sourcery
Make package creation transactional so generated stub databases are committed atomically and cleaned up safely on failure.
Bug Fixes:
Enhancements: