Bug 108066 - [prefs] core.prefs settings file causing repeating version conflicts
Summary: [prefs] core.prefs settings file causing repeating version conflicts
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Resources (show other bugs)
Version: 3.1.1   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 3.6 M6   Edit
Assignee: Martin Oberhuber CLA
QA Contact: Szymon Brandys CLA
URL:
Whiteboard:
Keywords: greatbug
: 143770 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-08-25 18:18 EDT by Neale Upstone CLA
Modified: 2010-03-01 04:58 EST (History)
6 users (show)

See Also:


Attachments
Relevant stack-traces when reproducing the issue (4.94 KB, text/plain)
2010-02-22 06:57 EST, Markus Schorn CLA
no flags Details
Clears the dirty flag after updating project prefs from file (1.66 KB, patch)
2010-02-23 08:55 EST, Markus Schorn CLA
mober.at+eclipse: iplog+
Details | Diff
Patch with slightly updated comments (1.82 KB, patch)
2010-02-23 12:17 EST, Martin Oberhuber CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Neale Upstone CLA 2005-08-25 18:18:17 EDT
At the top of the org.eclipse.jdt.core.prefs file in .settings, there is a line 
with a date stamp (#Thu Aug 18 15:28:50 BST 2005), which seems to get updated 
when no changes have been made to the settings.

We are using .settings extensively, and this is causing us problems, as we are 
ending up with conflicts, because this timestamp is getting updated when there 
are no changes to the actual content of the file, only to the timestamp.

Is the timestamp necessary, and if so, could it please be only updated on real 
changes to the file.
Comment 1 Neale Upstone CLA 2005-12-14 10:23:24 EST
This bug is still really annoying me, and continues into the 3.1.1 build.

 Can you at least justify the existence of that date stamp?

If not, I suggest removing the date stamp.
Comment 2 Frederic Fusier CLA 2005-12-14 13:40:31 EST
JDT/Core preferences rely on Platform Resources preferences and so I do not know whether this time stamp is used or not.
I'm currently tracking whether it's JDT/Core or Platform Resources which is responsible of this unnecessary update...
DJ, if you have any hits on this subject please let me know, thx
Comment 3 DJ Houghton CLA 2005-12-14 14:16:28 EST
I will check to ensure project prefs are behaving correctly w.r.t. isDirty and saving.
Comment 4 Frederic Fusier CLA 2005-12-15 09:01:31 EST
Seem to be a Platform preferences issue...

Not easy to reproduce. My scenario is to import in my workspace a project checked out in another workspace and not modified. Before, I put a breakpoint on last line of ProjectPreferences.read(ProjectPreferences node, IFile file).
For 3.2 M4 it's at line 394:
		Platform.getPreferencesService().applyPreferences(myNode);
When this bkpt is reached, toggle a watchpoint on EclipsePreferences.dirty field and you'll see while executing this last line that preferences are written although it should not...

I also verified all JDT/Core preferences possible update during this import and everything is clean (ie. no unnecessarily update is performed)

HTH
Comment 5 DJ Houghton CLA 2005-12-15 10:36:10 EST
Thanks for the investigation Frederic.
Comment 6 Frederic Fusier CLA 2006-05-29 04:59:27 EDT
*** Bug 143770 has been marked as a duplicate of this bug. ***
Comment 7 Neale Upstone CLA 2007-06-26 10:30:56 EDT
Glad to see this has been assigned.

There's another related scenario that has the same theme, that of XML config files (e.g. .project and .classpath) where the same information is output in a different order, therefore making it impossible to know what the change is that is being committed.

From a developers point of view, it's an annoyance in the same way as for .settings, as it looks like a change happened, but didn't, but makes changes difficult to spot.

Perhaps we need the "Compare files" to do so, not as text files, but as XML structure.
Comment 8 Markus Schorn CLA 2010-02-22 06:57:22 EST
Created attachment 159764 [details]
Relevant stack-traces when reproducing the issue

The issue can be reproduced in the debugger (using 3.6M4):

1) Set a breakpoint at the beginning of the RefreshJob.runInWorkspace(...)
2) Import a java-project with a file '.settings/org.eclipse.jdt.core.prefs'
--> The java indexer is notified about the new project and accesses the 
    project preferences. The preference node is created, an attempt to load
    them from file is made, however the file does not yet exist, so the node
    remains to be empty.

3) After that let the refresh job continue
--> When the file '.settings/org.eclipse.jdt.core.prefs' is refreshed, the
    existing empty project preference node is updated and marked as dirty. 
    It is not yet flushed to disk at this point (because flag isLoading is set).

    Note: If the project preference node does not yet exist at this point,
          it is created and loaded and updated. Then the update does not 
          actually change anything, so the node is not set dirty and we are
          fine)

4) Any operation that flushes the preference tree now causes the dirty node
  to be flushed to disk. E.g. a preference import will trigger that.
Comment 9 Markus Schorn CLA 2010-02-23 08:55:46 EST
Created attachment 159920 [details]
Clears the dirty flag after updating project prefs from file

The patch fixes the issue by clearing the dirty flag after applying the preferences as read from the file. 

The preference node may actually be modified through listeners at this point. Up to now, such changes were sometimes flushed to disk accidentially (when some other client flushed the entire preferece tree), but usually they were not persisted. 
With the patch such modifications will not be flushed, unless at a later point the node is further modified and flushed afterwards.
Comment 10 James Blackburn CLA 2010-02-23 09:50:27 EST
Is it also possible to suppress the date stamp in the preference file?  Most (all?) filesystems already have a modified time, so putting it in the prefs file seems overkill.
Comment 11 Markus Schorn CLA 2010-02-23 10:08:22 EST
(In reply to comment #10)
> Is it also possible to suppress the date stamp in the preference file?  Most
> (all?) filesystems already have a modified time, so putting it in the prefs
> file seems overkill.
That's a different issue and there is no trivial fix for that, the timestamp is written by java.util.Properties.store(..), which is used to persist the project preferences.
Comment 12 Martin Oberhuber CLA 2010-02-23 11:13:48 EST
Also, note that with Markus' fix, the timestamp in the properties file will change much less frequently so I do not think that this will be an issue any more.

And I do see some value in the timestamp since when you unpersist the project out of an archive, CM Repository, ... the timestamp on disk may be different than when the properties file was actually written.
Comment 13 James Blackburn CLA 2010-02-23 12:11:48 EST
(In reply to comment #12)
Yep, point taken. 

Markus' fix will make a big difference to the project deltas we see when using Eclipse with CCRC.
Comment 14 Martin Oberhuber CLA 2010-02-23 12:17:01 EST
Created attachment 159954 [details]
Patch with slightly updated comments

I slightly updated comments to reflect my understanding of what the patch does.

Markus: Would it make sense to compare the prefs-on-disk versus prefs-in-memory before resetting the dirty flag? I see that in the read() method, we already have the "original" prefs from file as well as the "merged/imported" ones, so this should be possible:

//if the node existed before importing, it is marked dirty although unchanged
if(node.isDirty() && comparePrefs(myNode, node)==0) {
    //reset dirty flag since prefs were not really modified
    node.setDirty(false)
}
Comment 15 Markus Schorn CLA 2010-02-23 12:52:03 EST
(In reply to comment #14)
> ...
> //if the node existed before importing, it is marked dirty although unchanged
> if(node.isDirty() && comparePrefs(myNode, node)==0) {
>     //reset dirty flag since prefs were not really modified
>     node.setDirty(false)
> }

I think the intended behavior is not to flush such changes. 
(The initial modifications to the preferences via a PreferenceModifyListener will be done every time the project is opened. So there is no actual need to
flush them.)

Even if you leave the dirty-flag set, the flushing will be suppressed. It's only done sometimes by accident. For example when you use the import wizard to import some workspace preferences this will as a side effect flush all dirty project preferences.
Comment 16 Martin Oberhuber CLA 2010-02-24 16:44:53 EST
I have committed the fix to HEAD (all AutomatedTests pass).

The important thing to understand here is that this fix does not protect us from race conditions, but it does make the effect of race conditions deterministic.

If a client is in the middle of updating project prefs when a refresh monitor forces re-loading preferences from disk, we get a version conflict which we cannot resolve: the content from disk overrides the content in memory, both before the fix and after. Before the fix, the preference node remained dirty thus indicating ("needs saving") and it was purely random who would ever perform a save on the next preference flush.

With the fix, after loading content from file, the in-memory representation correctly specifies the prefs node as unchanged compared to the disk, so no flush is needed, so we get the deterministic behavior of "file system is always king" and avoid the scenario where an unflushed prefs node remains hanging around forever.

So the fix definitely improves the situation, especially in the case of listeners modifying project prefs too early after project open, when prefs are not yet correctly initialized. In order to avoid race conditions, some more work would be needed elsewhere:
  - delay "project open" notification until after project prefs have been
    initialized
  - Ensure that project prefs cannot be refreshed from disk while a client 
    is editing them

I think that the 2nd case is mostly ensured today already, by flushing modified prefs immediately. In case the resource is out of sync while flushing, the flush runs into an error, so users are aware of potential problems.

Thanks Markus for all the investigations, this was a great bug to fix.