Community
Participate
Working Groups
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.14) Gecko/2009090216 Firefox/3.0.1 Build Identifier: CDO 2.0.0.v200906160459 During multiuser testing, with around 15 users performing frequent commits and refreshs, we are seeing duplicate CDOID/CDO_VERSION entries appearing in our database. Obviously these pairs should be unique, so this is data corruption. First, I'm a bit surprised that CDO doesn't put a uniqueness constraint on this compound key -- so "part 1" of this Bugzilla is a request to add that. Second, I am wondering: how does CDO protect against conflicting "updates" at the persistence level? Obviously an "update" is really a UPDATE+INSERT combination with the insert adding the new revision -- so what I mean is: how does CDO prevent two INSERTs from inserting two rows with the same CDOID/CDO_VERSION ? Since CDO has not put a uniqueness constraint on the compound key, this responsibily can not be assumed to be handled by the database. I am aware of the lockedObjects collection in TransactionCommitContextImpl, but these objects are released shortly after the DBStoreAccessor returns. So the assumption seems to be that once the DBStoreAccessor returns, the data has safely been written. But a DBMS will surely return before performing the actual write, if that's possible given constraints and isolation requirements. Note, the above is based on a somewhat hasty code review, so if I misunderstood something I apologize. Also, I must admit that we are still using Derby -- we'd like to switch, but for the upcoming release of our product we are too far down the development/test cycle for that. And at this stage we see no reason to assume that this is Derby-specific. Reproducible: Sometimes Steps to Reproduce: During multiuser testing, with around 15 users performing frequent commits and refreshs, we are seeing duplicate CDOID/CDO_VERSION entries appearing in our database. Obviously these pairs should be unique, so this is data corruption. First, I'm a bit surprised that CDO doesn't put a uniqueness constraint on this compound key -- so "part 1" of this Bugzilla is a request to add that. Second, I am wondering: how does CDO protect against conflicting "updates" at the persistence level? Obviously an "update" is really an UPDATE+INSERT combination with the insert adding the new revision -- so what I mean is: how does CDO prevent two INSERTs from inserting two rows with the same CDOID/CDO_VERSION ? Since CDO has not put a uniqueness constraint on the compound key, this responsibily can not be assumed to be handled by the database. I am aware of the lockedObjects collection in TransactionCommitContextImpl, but these objects are released shortly after the DBStoreAccessor returns. So the assumption seems to be that once the DBStoreAccessor returns, the data has safely been written. But a DBMS will surely return before performing the actual write, if that's possible given constraints and isolation requirements. So that seems to leave room for an update from a second session to be processed in such a way that it appears to have been serialized at the CDO level, but actually may be parallel at the database level. Admittedly, this above is based on my review of fairly complex code, so if the protection is there and I just overlooked it, I apologize. Also I must admit that we are still using Derby -- we'd like to switch, but for the upcoming release of our product we are too far down the development/test cycle for that. However, at this stage we see no reason to assume that this is Derby-specific.
One might wonder: why did I write most of the description here twice? Editing in a separate app, then clumsy pasting: once too often. Sorry guys. I would clean it up if I had the access rights. Anyway, please read it starting from "Steps to Reproduce:" Thanks /Caspar
Do I understand correctly that the version gets duplicated (not the ID - so i.e., we don't have two different objects getting the same ID but rather two different revisions of the same object getting the same version)? Also, can you please specify which store (DB?) and which database you are using? There should be unique constraints on the (CDO_ID, CDO_VERSION) columns. Can you use an SQL browser and login to your database and check if there are constraints (maybe wrong ones?)
There is only one non-unique index on (CDO_ID, CDO_REVISED).
Ok, I had a look at the sources. Indeed, we do not create UNIQUE indices. I don't exactly know why, though. I checked in the old DBStore sources and it this is not an omission during the DBStore-refactoring. We did not create unique indices in the old DBStore, either. So this bug is really two in my eyes: Bug 1: create UNIQUE (aka Primary Key) indexes (aka constraints) => handled in Bug 292146 Bug 2: even if UNIQUE constraints exist on the DB, they do not prevent the real problem (well, they would by failing the conflicting transaction). But shouldn't we catch conflicting concurrent version creation issues above the persistence layer itself?
OK, Bug 292164 has been taken care of, so that prevents database corruption. But CDO itself still doesn't adequately prevent conflicting concurrent updates. As I mentioned in the bug description, it seems that TransactionCommitContextImpl.lockedObjects field should prevent this, but this protection is evidently not airtight. One thing that looks suspicious to me, is that the new revisions are computed before the objects are locked (see TransactionCommitContextImpl.write). And since the essential check "originObject.isCurrent()" is performed in computeDirtyObject, this allows two or more threads to pass this test concurrently while in fact they are going to have a conflict. So, it seem to me that at least lockObjects() should be called before computeDirtyObjects(*). But perhaps there's more to it than this?
Created attachment 150585 [details] Patch for 2.0.0 A tiny patch. It should do the trick...
Yes, that makes sense ;-) Committed to R2_0_maintenance
Comment on attachment 150585 [details] Patch for 2.0.0 Jasper, please confirm that: 1) The number of lines that you changed is smaller than 250. 2) You are the only author of these changed lines. 3) You apply the EPL to these changed lines.
(In reply to comment #8) > (From update of attachment 150585 [details]) > Jasper, please confirm that: > > 1) The number of lines that you changed is smaller than 250. > 2) You are the only author of these changed lines. > 3) You apply the EPL to these changed lines. I confirm.
Available in 2.0.2: https://build.eclipse.org/hudson/job/emf-cdo-maintenance/44/artifact/result/site.p2/