tree hierachy (lft and rgt) being currupted on (accidentally) multiple submissions of an issue
|Target version:||Candidate for next minor release|
Frequently some user can accidentally press the 'Create' button twice (or more times) when creating a new subtask. In this case, not only the issue will be created a lot of times, but the issue tree will be corrupted.
I guess the insertion is being done without transaction isolation, and the lft and rgt fields are being calculated in the wrong conditions.
Although the bug reproduction depends on certain conditions, it's easy to reproduce it:
1. Press 'Add' to add some subtask to a existing issue
2. Fill some data in the new subtask
3. Press the 'Create' button a lot of times quickly, without wait the submit's end
After that, there will be some issues as grandson issues (not children issues as expected), but the parent task will be the right one.
I created a example of this problem on the redmine demo, at http://demo.redmine.org/issues/33583
All subtasks 'dd' in this example should be child of parent, but it's not this way.
I'm marking this as High priority because it corrupts the database without an easy fix.
#2 Updated by Mischa The Evil over 2 years ago
As visible on the demo I've been able to reproduce the described behaviour there.
I don't know though if it's something that should be fixed inside Redmine. This seems more of an issue that might affect more Rails-based apps. Though I might be wrong here... 8-)
#6 Updated by Bruno Medeiros about 2 years ago
Good to see it could be fixed soon. I can confirm this bug is still present on demo, and created another ticket there to demonstrate the problem:
All descendants of 2896 should be children, but they are shown in different (wrong) levels.
As I said above, I believe the fix applied to #6826 can fix this too, without much work. Please post here if you need some help with this.
#8 Updated by Bruno Medeiros about 2 years ago
Don't know much about RoR, but at least in Java we're used to make each request have its own transaction, making this approach harder than avoid the double click.
The only downside I see on using the 'avoid double click' solution is if more than one user tries to create children for an issue at the exactly same time, which is very unlikely.
#9 Updated by Etienne Massip about 2 years ago
there is no transaction and 2 successive DML (which explain #7667) : #save does the insert and #after_save => #update_nested_set_attributes does an update of the hierarchy.
Doing a single insert (that is, do not call #update_nested_set_attributes after save but before) can be buggy too.
Edit May, 11th : Actually, there is a transaction managed by RoR ActiveRecord.
#10 Updated by Alfredo Bonilla about 2 years ago
Hi, we have this problem in our installation too. Our "work around", re-create the task (duplicate) and re-do the parent relationship.
Here is part of the dump:
app/models/issue.rb:442:in `soonest_start' /var/lib/gems/1.8/gems/ruby-ole-220.127.116.11/lib/ole/support.rb:40:in `send' /var/lib/gems/1.8/gems/ruby-ole-18.104.22.168/lib/ole/support.rb:40:in `to_proc' app/models/issue.rb:442:in `soonest_start' app/models/issue.rb:272:in `validate' app/models/issue.rb:498:in `save_issue_with_child_records' app/models/issue.rb:487:in `save_issue_with_child_records'
#12 Updated by Bruno Medeiros about 2 years ago
Yes, you can do it, but need to take care. you should do a backup first just in case.
lft and rgt tell redmine how it should build the tree. They hold the visit and unvisit index on a depth-first search on the tree. Example:
- Parent (lft 1, rgt 10)
- Child 1 (lft 2, rgt 3)
- Child 2 (lft 4, rgt 9)
- Grandson 1 (lft 5, rgt 6)
- Grandson 2 (lft 7, rgt 8)
Parent is the first to be visited (lft=1), and the last to be unvisited (rgt=10), and so on... These should be calculated for all tickets with the same root. The root will have always lft=1 and rgt = #tickets * 2.
#17 Updated by Etienne Massip over 1 year ago
Gary Shi wrote:
(...) is there any scripts that could fix or recalculate lft/rgt values after a curruption?
Try to run
ruby script/runner -e production 'Project.rebuild!'
from your Redmine base directory.
Edit: I mean Issue.rebuild! but didn't try yet so I advise you to make a DB dump before.
#18 Updated by Matt Brown about 1 year ago
I found it possible to reset the parent/child relationships with:
UPDATE `redmine`.`projects` SET lft = 2 * id - 1, rgt = 2 * id;
Then adjust the subprojects relationship manually within the UI.
This will make each of the projects have no parents and no subordinates (as their left [bookend] and right [bookend] are just one number apart).
Knowing this is how the relationship is derived, should allow you to isolate problems more easily. You can actually remove sub-projects just by not having a lft and rgt number within a parent project's lft-rgt range.
I worked hard to migrate from 0.8.4 to 1.3.1 and had to deal directly with the DBs where this situation came into play.
#19 Updated by Eugene Hutorny 12 months ago
Hit this issue with the following scenario:
Two users concurrently update two different issues and assign the same parent id to both of them.
Hierarchy of the parent task becomes broken and access to its children may cause process hanging or crashing.
SQL for detecting broken hierarchies:
select distinct parent_id from issues where parent_id is not null group by parent_id, rgt having count(*) > 1
#23 Updated by Antoine Beaupré about 1 month ago
Note that this also affects projects on Redmine 1.4.
The workaround is to run:
X_DEBIAN_SITEID=koumbit RAILS_ENV=production ./script/runner 'Project.rebuild!'
(X_DEBIAN_SITEID= is a local hack in the debian package.) This will rebuild the lft and rgt columns that are corrupted. It may mean that the order of projects changes, but the parent/child relationship will stay.