Eclipse Platform Core RFC 0001
Case Variant Collisions During Resource Creation.
Summary
The Eclipse workspace is always case-sensitive, but some filesystems are not. This causes
a problem when trying to create a file using the Core API, in the case where
a file already exists at the target location that differs only in case from the file being created.
This document discusses the problem and evaluates various approaches to solving it.
By John Arthorne, OTI.
Created: November 26, 2001
Last Modified: January 4, 2002
The Problem
Let us define three resource handles:
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("Project");
IFile abc = project.getFile("abc.txt");
IFile ABC = project.getFile("ABC.txt");
The initial state of the problem is when project and abc already exist.
If a Core API method is used to create ABC (using either create, copy,
or move API methods), an exception is thrown. The exception
detail states that the file could not be created because it already exists. The contradiction
is that ABC.exists()will return false, since the case sensitive workspace does not
recognize the collision with abc. Likewise, lookup methods such as
project.findMember("ABC.txt") will also fail to locate the existing file abc,
leading the API user to believe that it is ok to go ahead and create ABC.
Note that this is not quite the same as when a case variant already exists in the file system,
but not in the workspace. Following the above example, say a local file "abc.txt" does not
exist in the workspace, but is created externally in the filesystem. In this case, the current
behaviour when a client calls ABC.create() is consistent; it throws an exception
stating that the workspace is out of sync with the local filesystem.
New comment:
It should be noted that this problem arises from the fact that the platform case sensitivity
does not always match the case sensitivity of the underlying filesystem. In most cases,
this inconsistency can be handled by the platform core without requiring special handling
by callers of core API. However, this situation represents one rare corner case that cannot be
resolved silently. This is because "under the covers" resolution would require core to
delete files from the filesystem without user awareness.
Proposed Solution
The proposal is to add a new core status code, IResourceStatus.CASE_VARIANT_EXISTS.
This status code would be included in exceptions from all create, copy,
or move API methods in the IResource hierarchy, when a case variant already exists
at the target location. The exception will also include an appropriate error message
describing why the creation couldn't continue.
Pros:
- This solution allows clients to recognize the situation and act accordingly. Core cannot determine
the appropriate behaviour for all cases when this problem occurs, so the decision must
be left to the caller. For example, say a resource "/Project/abc/myfile.txt" already exists.
A client wants to create a file called "/Project/ABC/anotherfile.txt". When they attempt to
create folder ABC, a failure occurs because of the case variant collision. In this situation,
the caller may know that the case of the folder isn't important, and they'll just go ahead and create
"/Project/abc/anotherfile.txt". In another situation, the caller may decide it is better
to delete the existing "abc" folder, and create the new "ABC" folder in its place. In a third situation,
the client may decide to defer the question to the user.
- Minimal impact on downstream clients. This fix requires no breaking API changes, and the
new behaviour is similar to the old behaviour. In both new and old approaches, an exception is
thrown -- the only thing that has changed is the status code.
Cons:
- Status codes are fuzzy API. API methods do not formally guarantee what status
codes will be returned for a given error condition. The status codes could theoretically
change at any time without warnings or deprecations.
New comment: while the status codes returned by a particular
method are technically fuzzy, we strive to avoid changing return status codes without a
very compelling reason and sufficient advance notice. The code constant and value are API
and will not change.
- Feedback: There is still an inconsistency between the behaviour
of exists and create.
Feedback: Each project can be associated with a different repository
and the versioning abilities of that project are governed by the target repository (adapter).
It seems strange that we would not argue that a project's case sensitive behavior wouldn't
be based on the target file system it was stored on.
Response: Yes, you could argue that this approach would give a more
consistent user experience. However, this would unfortunately require a radical redesign
and a major overhaul of large amounts of platform code. What this solution proposes
is the best we could come up with under the constraints of the existing architecture.
Alternative Solutions
This section describes proposed alternative solutions, and some comments on them.
More alternative solutions will be added as they are raised during discussion. Please
feel free to add to or dispute any pros and cons already listed.
Make the Workspace Case-Sensitivity Match the Filesystem
With this approach, when the Eclipse workspace is run on a case-insensitive operating
system, the workspace would never be case-sensitive. On case-sensitive operating
systems, the workspace would always be case-sensitive.
Pros:
- Behaviour is consistent with the underlying filesystem
- Core API methods are always consistent with each other. If there is a failure
to create because the target already exists, then exists and findMember
methods will also find the target in all cases.
Cons:
- Performance. This approach would have a huge performance cost. The critical
performance path for the workspace is lookups in the resource tree. This lookup
is based on a high performance binary search in the resource tree. This search cannot
be performed as efficiently when ignoring case.
- Inconsistency gets pushed up to higher layers. In many cases this approach
merely moves the file-system inconsistency problems up to other plugins. Callers of
Core API can currently rely on it always being case-sensitive, and can act accordingly.
Core is able to handle some of these inconsistent situations without involving client
plug-ins.
Feedback: You could argue that providing a case sensitive workspace
in the absence of a case sensitive file system is also pushing up an inconsistency to layers
above that may also need to deal with external tools?
- Inconsistencies still possible when workspace spans filesystems. If the
user has a workspace where some projects are mounted on a case-sensitive
filesystem, and others are mounted on a case-insensitive filesystem, there would still be
an inconsistency. Such a setup would undoubtedly cause widespread problems for
downstream plug-ins trying to manage such an inconsistent workspace.
Related Bugs:
RFC Status
This proposal is has been voted on and accepted.