-
Notifications
You must be signed in to change notification settings - Fork 40
Prevent broken transactions when autonumbering #7671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v7.11.4-prerelease
Are you sure you want to change the base?
Conversation
|
There previously was an issue with the This issue has been fixed! |
Replaces #5404
Fixes #4148, #7560
Addresses part of #5337
Checklist
self-explanatory (or properly documented)
This branch should functionally be the equivalent of #7455, based on
v7.11.3instead ofmain.The Pull Request seeks to address an issue related to the prior autonumbering code, where database transactions could become broken due to a
LOCK TABLESstatement within transactions:See #6490 (comment)
Currently in
main, this autonumbering behavior with the WorkBench can result in a functionally complete lockout of the database, preventing other connections from reading tables like Discipline and Collection until the WorkBench operation finishes.Below is a video of the issue taken in
v7.11.3:v7_11_3_wb_issue.mov
Below is with the changes in this branch:
v7__11_3_wb_fix.mov
(Developer-Focused) New Internal Autonumbering Design
Specify now uses transaction-independent User Advisory Locks to determine which session is currently using autonumbering for a particular table. If no other sessions currently have the autonumbering lock for a particular table, a connection will acquire the lock.
If a record attempts to autonumber a field that is being autonumbered by another session (e.g. another session holds the autonumbering lock), Specify will wait up to 10 seconds for the prior connection to release its lock. If the lock is not released by that time, then Specify will error out of the operation.
To maintain autonumbering behavior for concurrent actions where there is a long-running transaction also doing autonumbering (such as when a long-running WorkBench operation is ongoing), Specify uses Redis (for IPC) to store the currently highest autonumbering behavior for a particular formatter.
When a sessions holds an AutoNumbering lock for a particular table, it checks this store for the highest automumber and compares it to the highest value the session can see in the database: using the higher of the two to determine the new highest value.
Thus, even with transactions that have a high Isolation Level, Specify is still internally committing the AutoNumbering values to the store that can be accessed by other sessions.
Roughly, this means that AutoNumbering acts at a similar isolation level to READ UNCOMMITTED within the application.
The core part of the implementation of this design is through the new
LockDispatcherclass:specify7/specifyweb/specify/models_utils/lock_tables.py
Lines 202 to 258 in 4de5c06
This class can be used as a context manager and handles acquiring and releasing User Advisory Locks:
The
AutonumberingLockDispatcherbuilds the IPC (Redis) integration required for AutoNumbering on top of the baseLockDispatcherclass, which handles the database locks.specify7/specifyweb/specify/utils/autonumbering.py
Lines 39 to 84 in 4de5c06
(User-Focused) New Autonumbering Behavior
Below is graph which simply describes the new behavior
flowchart TD A[WorkBench 001] --> B[WorkBench 002] B l1@-- waiting for DataEntry--> C(.) B -- concurrent record saved --> D(DataEntry 003) C l2@-- DataEntry finished--> E(WorkBench 004) D --> E classDef wb stroke:#f00 classDef de stroke:#00f classDef dashed stroke-dasharray: 5 5 class A,B,C,E wb; class D de; class l1,l2 dashedAll AutoNumbering operations are processed serially. This means if there's an ongoing Workbench operation that creates a record that is numbered
01, the next autonumbering value for any other session will be02.If the Workbench were to create another record, it would be numbered
03.Testing instructions
Sample Database
To speed up setup for testing this Pull Request, i've set up a testing database that contains all resources required for testing:
Feel free to use the database!
issue-6490_testing.sql.zip
General Concurrency with WorkBench
Concurrent Autonumbering with the WorkBench
Concurrent Autonumbering with Non Collection Scoping
Review Table Scoping Hiearchy for an overview on table scopes
With the Sample Database, this would be using the Locality Data Set in the Plants Collection with creating a new Locality in the Vascular Plants Collection
General