Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign updo not lose folders after rename and checkout #34
Comments
|
This issue exposes a significant and somewhat complex difference between the current Windows and Mac implementations. The fundamental challenge is how to track not-yet-fully-hydrated directories and files if any of their ancestor directories are renamed. In the Windows case, the On Mac, however, projected directories are converted to full, regular ones once all their immediate children have been enumerated. The consequence is that they can then be renamed, which could cause any not-yet-projected descendants lower in their hierarchy to be "lost" -- i.e., their new paths would not correspond to any paths the provider was able to retrieve from its upstream data source. So on the Mac, when a rename event is detected on a directory, the kext first sends a request to the Another factor to consider is that on both systems, it is possible -- even necessary -- for the GVFS provider (unlike
Note that we currently, on Linux, have inherited the Mac logic to mark directories as needing re-expansion. Given these constraints, we are faced with one of two or maybe three options:
This final, somewhat hypothetical option might be able to combine the best of both worlds, by avoiding unbounded recursion -- which necessitates rejecting rename operations when any descendent is not yet populated; not ideal, but at least a clean model which matches the Windows implementation -- but yet allowing directories to become full ones where we can. The key would have to be that libprojfs would need to reject rename operations on directories in a non-full state, and directories would need to be moved into a populated/hydrated state after being enumerated, rather than being moved directly to the full state as they are now. A hydrated directory would have a second xattr, When a new projected file or directory was created outside of an enumeration callback, we would need to first traverse the path down from the mount point, marking each full ancestor directory (if any) as non-full, with a count of zero. Then the requested file or directory would be created, and the path traversed upwards again, incrementing the count on each ancestor. One nice property of this logic would be that, once a directory was marked non-full, it could not be renamed -- and so race conditions with other rename operations would be impossible; we couldn't "lose" our ancestors if an intermediate directory was renamed while we were creating the new projected file, for example. We could race with deletion operations, but that would be acceptable, as deletion can occur at any time. If an error occurs while creating the new projected file or directory, or some other error occurred, we would want to try recursing back upwards, making the ancestors full again and removing the zero-value count xattr. This recursion could, of course, experience it own failures, but the worst-case scenario would be that we could leave some directories marked as non-full when they could, possibly, be converted to full. Deletion of non-full files and directories would also need to decrement their parent's count value, and possible recurse upwards if the parent became full as a result. |
The following currently fails on Linux (assuming
Foois an un-hydrated folder present in the repository), because althoughBaris removed by the finalgit checkout,Foois not restored: