Issue #159: Send final modifications before remove operation#170
Issue #159: Send final modifications before remove operation#170roundhill merged 10 commits intoSimperium:developfrom
Conversation
- Added a method that will return the backup copy if retrieval from persistent store fails
- Fixes an issue found in Simplenote where deleting and trashing a note right after modifying it could cause the deletion not to reach the server. This was due to an object in the backup store having an outdated ghost.
…cket - Promoted Channel.isIdle() to a method of the Bucket.Channel interface - Added a unit test for consecutive saving and deleting of two notes (also tests backup store clearing)
- Fixes an issue where calling BucketObject.save() and then immediately BucketObject.remove() on a multi-core device could result in the remove operation being sent to the ChangeProcessor before the modify operation
…ception' into issue/159-concurrency-exception
…her than wait a fixed time
|
Fixed a unit test that failed on Travis. The problem was that Travis' single-threaded emulator didn't process the threads fast enough for the fixed time the test was waiting. I changed the test to wait for |
|
Looks ok, I hooked it up to Simplenote and syncing was functioning as it should although I couldn't get it to get into a situation where the lock was applied. @aforcier maybe you have some tips on how to get it to reproduce in Simplenote? Otherwise the tests pass and the code looks good 👍 @beaucollins you can have final say before merging? |
|
@roundhill, I wasn't able to reproduce the issue by normal usage of the app. What I had to do in testing was modify the 'Move to trash' operation to also remove the note from trash as soon as it's flagged |
|
|
Issue #159: Send final modifications before remove operation
Fixes #159. The fix stores a backup copy of the object whenever
BucketObject.save()is called. WhenChangeProcessorrequests the object to produce the diff, it's given the backup copy if the master is missing from the persistent store.I found that there's a second way a remove operation can be sent to the server before a modification that preceded it. This is a concurrency issue caused by a multi-threaded
ExecutorinBucketsometimes running theremove()thread before thesync()thread, and can happen if there is nearly no delay betweenBucketObject.save()andBucketObject.delete()(for example, a 20ms delay between them was enough for the bug not to happen in testing on Simplenote). In this case the remove operation is sent to theChangeProcessorfirst and the object is deleted on the server without its final modification.I addressed the second issue by adding thread locking to
sync()andremove()in Bucket, so thatremove()always runs aftersync()is completed for the same object. I also added aConcurrencyTestunit test class, which tests this fix on a multi-threadedExecutor.