| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
WalkthroughRefactors Connection in crates/stdlib/src/sqlite.rs to use concurrency-safe primitives: adds initialized: PyAtomic<bool>, converts detect_types, check_same_thread to atomics, changes thread_ident to a mutex, and updates init/reinit, close, and thread-checking flows plus helper functions drop_db and reset_factories. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant C as Connection
participant S as SQLiteDB
participant A as Atomics
U->>C: __init__(params)
C->>A: initialized.store(false)
C->>S: open database
alt DB open succeeds
C->>A: set detect_types / check_same_thread
C->>C: set thread_ident (PyMutex)
C->>A: initialized.store(true)
C-->>U: return
else DB open fails
C->>A: ensure initialized stays false
C-->>U: raise Error
end
U->>C: execute / executemany
C->>A: if !initialized.load() -> raise ProgrammingError
alt initialized == true
C->>A: check_same_thread.load()
C->>C: lock thread_ident if needed
C->>S: execute statement
C-->>U: result
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
📜 Recent review details Configuration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro 📥 CommitsReviewing files that changed from the base of the PR and between ece048d and c9fc8a7. 📒 Files selected for processing (1)
crates/stdlib/src/sqlite.rs (5) 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. ❤️ ShareComment @coderabbitai help to get the list of available commands and usage tips. |
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)crates/stdlib/src/sqlite.rs (1)📜 Review details906-906: Consider stronger memory ordering for the initialized flag.
Using Ordering::Relaxed for the initialized flag swap may not provide sufficient synchronization guarantees across threads. When one thread sets initialized to true (line 934), another thread reading it with Relaxed ordering might not see the updated value promptly, or might observe it out of order with respect to other field updates.
Consider using Ordering::AcqRel for the swap and Ordering::Release when storing (line 934) to ensure proper synchronization.
Apply this change for stronger guarantees:
- let was_initialized = zelf.initialized.swap(false, Ordering::Relaxed); + let was_initialized = zelf.initialized.swap(false, Ordering::AcqRel);And at line 934:
- zelf.initialized.store(true, Ordering::Relaxed); + zelf.initialized.store(true, Ordering::Release);
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 CommitsReviewing files that changed from the base of the PR and between f7ddcd2 and 216ab89.
⛔ Files ignored due to path filters (1)crates/stdlib/src/sqlite.rs (6)836-840: LGTM! Thread-safe field wrappers are appropriate.
The atomic wrappers for detect_types and check_same_thread, plus the mutex for thread_ident, correctly enable thread-safe access to these fields that are read outside the db mutex protection. The initialized flag properly tracks initialization state for re-initialization handling.
869-880: LGTM! Constructor initialization is correct.
The initialization logic properly sets initialized to true for base classes (where db is initialized immediately) and false for subclasses (where __init__ must be called). The use of Radium::new for atomic fields is appropriate.
905-936: Potential race condition with concurrent re-initialization.
If two threads concurrently call __init__ on the same Connection object, they could interleave their operations unpredictably:
- Both threads swap initialized to false
- Both threads reset factories and drop the database
- Both threads open new databases
- Both threads try to store their database handle, with the second overwriting the first (leaking the first connection)
While concurrent __init__ calls are uncommon in typical Python usage, this is technically a data race. Consider documenting that __init__ must not be called concurrently, or add protection against this scenario.
941-949: LGTM! Helper methods are correct.
The drop_db and reset_factories helper methods correctly encapsulate their respective cleanup operations. Note that close() calls drop_db but doesn't reset the initialized flag, though this doesn't cause incorrect behavior since _db_lock checks db.is_some() rather than the flag directly.
1484-1495: LGTM! Atomic field access is correct.
The check_thread method correctly uses load() for the atomic check_same_thread field and lock() for the mutex-protected thread_ident. The Relaxed ordering is acceptable here since these are configuration checks.
1668-1669: LGTM! Atomic detect_types access is correct.
All sites correctly read detect_types using load(Ordering::Relaxed) from the atomic field. The Relaxed ordering is appropriate for reading this configuration field.
Also applies to: 1717-1718, 1883-1884
Sorry, something went wrong.
There was a problem hiding this comment.
👍
Sorry, something went wrong.
|
Could you check this comment? #6288 (review) This sounds reasonable. And because it is initialization step, we don't have much disadvantage to use more stronger ordering. |
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review detailsConfiguration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 CommitsReviewing files that changed from the base of the PR and between 5150186 and b2f3adf.
📒 Files selected for processing (1)crates/stdlib/src/sqlite.rs (6)836-843: LGTM! Struct changes properly support reinitialization tracking.
The addition of the initialized flag and conversion of configuration fields to atomic types correctly enables tracking initialization state and thread-safe access. The use of PyMutex<ThreadId> is appropriate given the TODO comment and platform constraints.
869-880: LGTM! Initialization correctly distinguishes base vs. subclass construction.
The logic properly initializes the database immediately for the base Connection class while deferring initialization for subclasses until __init__ is called. The atomic field initialization using Radium::new is appropriate.
941-949: LGTM! Helper methods correctly manage connection state.
The drop_db and reset_factories methods appropriately encapsulate state management. The use of unsafe swap operations is consistent with the existing codebase patterns for PyAtomicRef.
1483-1495: LGTM! Thread checking correctly uses atomic flag and mutex.
The implementation properly loads the check_same_thread configuration flag atomically and locks the mutex to safely access thread_ident. The use of Ordering::Relaxed for the configuration flag is acceptable since it doesn't require synchronization with other state.
1668-1669: LGTM! Consistent atomic loads for configuration values.
The atomic loads of detect_types with Ordering::Relaxed are appropriate throughout the codebase. Since this is a configuration value that doesn't require synchronization with other mutable state, relaxed ordering is sufficient and provides good performance.
Also applies to: 1717-1718, 1883-1884
908-917: No action required—factory reset timing matches CPython behavior.
CPython's sqlite3.Connection does reset row_factory and text_factory during init reinitialization. The code correctly resets factories before the database open attempt, aligning with CPython's reinitialization approach. CPython's own reinitialization is documented as having inconsistent timing between text_factory and row_factory, and the implementation here matches that behavior.
Sorry, something went wrong.
Apply code review feedback to use Ordering::AcqRel for the swap operation and Ordering::Release for the store operation to ensure proper synchronization across threads when setting the initialized flag.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)crates/stdlib/src/sqlite.rs (2)📜 Review details1483-1495: Thread safety check correctly updated to use atomic primitives.
The method properly reads check_same_thread atomically and uses the mutex for thread_ident. While check_same_thread uses Relaxed ordering, this is acceptable because:
- The subsequent db_lock() call provides additional synchronization via the database mutex
- Thread checks happen before every operation, so any transient staleness during reinitialization is brief
- Reinitialization is rare (typically tests or error recovery)
If you want stricter guarantees, consider using Acquire ordering for the check_same_thread load to synchronize with the Release store in init at line 934. However, this is optional since the current approach is likely sufficient for practical usage.
- if self.check_same_thread.load(Ordering::Relaxed) { + if self.check_same_thread.load(Ordering::Acquire) {
1668-1669: LGTM: detect_types correctly read atomically in cursor operations.
The consistent use of Ordering::Relaxed for detect_types loads is acceptable because:
- These reads occur within operations that have already called db_lock(), providing synchronization via the database mutex
- Type detection behavior is not safety-critical
- Reinitialization-induced staleness would be transient and rare
Similar to check_same_thread, you could optionally use Acquire ordering for these loads to establish a stronger happens-before relationship with the Release store during initialization (line 934), but this is not necessary for correctness in typical usage patterns.
Also applies to: 1717-1718, 1883-1884
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 CommitsReviewing files that changed from the base of the PR and between b2f3adf and ece048d.
📒 Files selected for processing (1)crates/stdlib/src/sqlite.rs (5)834-843: LGTM: Struct fields correctly updated for thread-safe reinitialization.
The addition of the initialized atomic flag and conversion of detect_types and check_same_thread to atomics enables proper state tracking during reinitialization. The TODO comment on thread_ident is acknowledged in the PR comments.
854-883: LGTM: Proper initialization for both base and subclass Connection instances.
The initialization correctly handles the base class (immediate DB setup) vs. subclass (deferred setup) distinction, and properly initializes all atomic fields.
902-937: LGTM: Reinitialization logic correctly implements CPython-compatible behavior.
The initialization sequence properly handles the requirements from issue #6287:
- Atomically marks connection as uninitialized (line 906 with AcqRel ordering)
- Resets factories to defaults (line 909), matching CPython behavior
- Opens DB before mutating other state (line 917), so failures leave the connection uninitialized and subsequent operations raise ProgrammingError
- Only marks initialized on success (line 934 with Release ordering)
The memory ordering has been improved from the previous version, now using AcqRel for the swap and Release for the final store, which is stronger than the past review's suggestion and aligns with the maintainer's comment that "using stronger ordering has little downside" for initialization.
Based on learnings from past review comments.
941-949: LGTM: Helper methods correctly encapsulate reinitialization concerns.
drop_db and reset_factories cleanly separate the resource cleanup and default restoration logic, matching CPython's connection reinitialization behavior.
1039-1043: LGTM: Refactored to use the drop_db helper for consistency.
Sorry, something went wrong.
|
Code has been automatically formatted The code in this PR has been formatted using cargo fmt. Triggered by commit: ece048d0be2079e2f9a808c634f744769dbb1d17 You may need to pull the latest changes before pushing again: git pull origin fixed-issue-6287 |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Fixed #6287
reference
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.