A newsgroup participant recently asked:
After interrupting delete operations there may be orphaned objects. Those may have been branched to other objects that are still live in the database, so the history of the live object is stored in the orphaned object files. To be able to access the early versions, the orphaned object files are thus required. Is it possible to repair that situation or do I have to keep the files for the orphaned objects (and accept a lot of 'corrupt' information during analyze), or accept losing the live object history? Does the 'analyze -d' keep the files for such orphaned objects that have been branched? In that case it would be better to use analyze -d to delete orphaned not-used file-objects while files for orphaned project-objects must be removed manually. If the delete operation would have finished without interruption, would the history then be moved from the file of the deleted object to the branched live object(s)?
After interrupting delete operations there may be orphaned objects. Those may have been branched to other objects that are still live in the database, so the history of the live object is stored in the orphaned object files. To be able to access the early versions, the orphaned object files are thus required.
Is it possible to repair that situation or do I have to keep the files for the orphaned objects (and accept a lot of 'corrupt' information during analyze), or accept losing the live object history?
Does the 'analyze -d' keep the files for such orphaned objects that have been branched? In that case it would be better to use analyze -d to delete orphaned not-used file-objects while files for orphaned project-objects must be removed manually.
If the delete operation would have finished without interruption, would the history then be moved from the file of the deleted object to the branched live object(s)?
These are some good questions and cover some areas we're improving for VSS 2005. Let's first define some terms and discuss some details of branching and history. Then we’ll look at how delete or destroy operations on a branched file should work. Finally we’ll examine what can happen when an operation is interrupted and discuss how to recover from this situation.
Suppose we branch $/Proj1/foo.cpp to $/Proj2/foo.cpp. We refer to the file branched from ($/Proj1/foo.cpp) as the "branch parent" and the file branched to ($/Proj2/foo.cpp) as the "branch child". The relationship between branch parents and branch children is one to many. A branch parent can have many children, but each branch child has one and only one parent. Branch children can also be branch parents. That is, we can branch $/Proj1/foo.cpp to $/Proj2/foo.cpp and then branch $/Proj2/foo.cpp to $/Proj3/foo.cpp. $/Proj1/foo.cpp is the branch parent of $/proj2/foo.cpp, which is the branch parent of $/Proj3/foo.cpp.
When a file is branched, SourceSafe makes a new copy of the file and starts a new history log for the branch child. The first entry in the history log indicates that a branch occurred and refers to the branch parent. This makes the history of the branch parent available to the branch child, but note that the branch parent's history is NOT copied to the branch child's history log.
When we "delete" a file, SourceSafe only marks the file as deleted. The history and tip version are not physical removed but instead are retained so that the user can recover the file later if desired. Only when we "destroy" a file does SourceSafe actually do a physical removal. Even when we destroy a file, SourceSafe won’t actually remove it if it is a branch parent. Even though it doesn’t show up in SourceSafe Explorer, and we can’t recover it, the branch parent is still there to supply history for its branch children.
Now we get to the part where I have to admit that VSS 6 has some bugs. If we have a destroyed branch parent, and if it’s last branch child is also destroyed, then VSS should do a physical removal of the branch parent and reclaim the space it has been using. Unfortunately VSS 6 doesn’t do this, and neither does analyze v6 detect and remove these unused branch parents. This normally isn’t a big deal, since nothing refers to these "orphan" files. Some users, though, do a lot of branching, and eventually these orphan files may represent a significant chunk of the disk space used by their database. The good news is that for VSS 2005 we have improved orphan detection and removal for analyze and will now be able to remove these and other orphan files and reclaim their space. You need to specify the –d switch for analyze to try to remove unused files.
So far we’ve been talking about normal VSS operations. What if we lose connection to the database in the midst of a delete or destroy operation? VSS 6 has all its intelligence on the client. The "server" is really just a file share for the database. By design the client tries to be as fault tolerant as possible, but it can’t be truly "transactional" in the same sense as SQL Server for example. A delete operation, however, is comparatively safe. SourceSafe just makes a log entry in the parent project’s history and sets a flag in the parent project’s list of children to mark the item as deleted. A network interruption could occur between writing the log entry and setting the flag, but analyze can easily fix this. In any event no files are physically removed from the database. When a delete operation is applied to a project tree, SourceSafe really deletes just the project at the root of the tree. Since this project will no longer be visible from the UI, no action is needed on its children.
A destroy operation is more complicated and can cause some of the problems the poster was concerned with. To destroy an item, we make an entry in the parent project’s history, remove the item from the list of children, and then physically remove the files associated with the destroyed item. Furthermore, if we are destroying a project, we have to recursively destroy its children. But that’s not all. If a destroyed item has branch children, we have to retain its history, since the branch children rely on it. Obviously this can represent many round trips on the network. A large recursive destroy operation can take some time, and if we lose network connection during this operation, we’re likely to leave orphans.
As I mentioned above VSS 6 is not as smart as it might be about orphan removal, but it is aware of branch relationships, so it won’t remove any history that we still need. If you have a database where an interrupted destroy operation has left orphans, you can safely run analyze on it. Analyze v6 may not completely clean up the orphans, but it will retain any required history. Analyze 2005 will do a much better job cleaning up the orphans while still retaining required history.
In general interrupting a long recursive operation by terminating the VSS process can cause "bad things" to happen. There is, however, a cancel button that appears in the lower left corner of VSS Explorer during long operations. You can use this to safely cancel an operation. It’s also best to avoid running long recursive operations over an unreliable connection. If you do end up in this situation, running analyze is a safe thing to do, and it will at least partially clean up the database. VSS 2005 analyze will do better and is backwards compatible with VSS 5 or VSS 6 databases. If you still have database problems after running analyze, contact product support. A VSS 6 license comes with 2 free support incidents, and the VSS product support team has additional tools for dealing with database corruption issues.
- Rich Knox [MSFT]This posting is provided "AS IS" with no warranties, and confers no rights.