SVNRepository.status() vs. SVNRepository.getDir()

Here we will show how you can fetch properties from the repository recursively in a single request using SVNRepository. Many newbie users who come across the SVNRepository interface for the first time, decide to implement the task of recursive retrieving properties from a repository tree with the help of SVNRepository's getDir() method. To get properties recursively you'll have to call getDir() in recursion. It's not a wrong way, but consider the repository tree with multiple leaves (with hundreds or maybe thousands of them). For each directory leave getDir() sends a new request what leads to extremely slow performance.

Basically, what you do with getDir() is the following:

   1     public void fetchPropsFromRepository(SVNRepository repos, String path, long revision, 
   2                                          Map pathsToProps) throws SVNException {
   3         SVNProperties props = new SVNProperties();
   4         Collection children = repos.getDir(path, revision, props, SVNDirEntry.DIRENT_ALL, null);
   5         pathsToProps.put(path, props);
   6         for (Iterator childrenIter = children.iterator(); childrenIter.hasNext();) {
   7             SVNDirEntry childEntry = (SVNDirEntry) childrenIter.next();
   8             if (childEntry.getKind() == SVNNodeKind.DIR) {
   9                 String childName = childEntry.getName();
  10                 String childPath = !"".equals(path) && !path.endsWith("/") ? 
  11                                    path + "/" + childName : path + childName;
  12                 fetchPropsFromRepository(repos, childPath, revision, pathsToProps);
  13             }
  14         }    
  15     }

So, you simply call getDir() recursively storing properties on the way. But as it has already been mentioned, each call to getDir() results in one more request to the server. Instead you may use SVNRepository's status() method to fetch all the properties with the following benefits:

Status is an update-like operation, it follows the same concepts described in Describing a local tree to the server, but in contrast to update() status operation does not request file deltas what results in much lesser amount of data passed over the network. As in a basic update operation you have to report to the server what you already have locally. In this case saying that we are 'still emtpy' will do:

   1             final long rev = repos.getLatestRevision(); 
   2 
   3             ISVNReporterBaton reporter = new ISVNReporterBaton() {
   4                 public void report(ISVNReporter reporter) throws SVNException {
   5                     reporter.setPath("", null, rev, SVNDepth.INFINITY, 
   6                             true/*we are empty, take us all like in checkout*/);
   7                     reporter.finishReport();
   8                 }
   9             }; 

Paths reported by ISVNReporterBaton are relative to the location of SVNRepository. In the previous code snippet we say that we would like the server to send us all paths under the location of our SVNRepository accessor recursively as they exist in the HEAD revision. As a result, the server will describe the repository tree under that same path as it exists in the requested revision. Describing is performed via calls to our implementation of ISVNEditor. For the task of fetching properties we need to implement only those methods of ISVNEditor without which we could not match repository paths to their properties:

   1     private static class PropFetchingEditor implements ISVNEditor {
   2         private LinkedList myDirectoriesStack = new LinkedList();
   3         private Map myDirProps = new HashMap();
   4         private Map myFileProps = new HashMap();
   5         
   6         public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException {
   7             String absouluteDirPath = "/" + path;
   8             myDirectoriesStack.push(absouluteDirPath);
   9         }
  10 
  11         public void changeDirProperty(String name, SVNPropertyValue value) throws SVNException {
  12             //filter out svn:entry and svn:wc properties since we are interested in regular properties only
  13             if (!SVNProperty.isRegularProperty(name)) {
  14                 return;
  15             }
  16 
  17             String currentDirPath = (String) myDirectoriesStack.peek();
  18             Map props = (Map) myDirProps.get(currentDirPath);
  19             if (props == null) {
  20                 props = new HashMap();
  21                 myDirProps.put(currentDirPath, props);
  22             }
  23             props.put(name, value);
  24         }
  25 
  26         public void changeFileProperty(String path, String propertyName, SVNPropertyValue propertyValue) throws SVNException {
  27             //filter out svn:entry and svn:wc properties since we are interested in regular properties only
  28             if (!SVNProperty.isRegularProperty(propertyName)) {
  29                 return;
  30             }
  31 
  32             String absolutePath = "/" + path;
  33             Map props = (Map) myFileProps.get(absolutePath);
  34             if (props == null) {
  35                 props = new HashMap();
  36                 myFileProps.put(absolutePath, props);
  37             }
  38             props.put(propertyName, propertyValue);
  39         }
  40 
  41         public void closeDir() throws SVNException {
  42             myDirectoriesStack.pop();
  43         }
  44 
  45         public void openDir(String path, long revision) throws SVNException {
  46             String absoluteDirPath = "/" + path;
  47             myDirectoriesStack.push(absoluteDirPath);
  48         }
  49 
  50         public void openRoot(long revision) throws SVNException {
  51             String absoluteDirPath = "/";  
  52             myDirectoriesStack.push(absoluteDirPath);
  53         }
  54 
  55         public Map getDirsToProps() {
  56             return myDirProps;
  57         }
  58         
  59         public Map getFilesToProps() {
  60             return myFileProps;
  61         }
  62         
  63         //here go the rest of ISVNEditor's methods which we do not need to 
  64         //implement for our task
  65         ...
  66     }

Finally, having got a reporter and an editor we call 'status()' itself:

   1             //run an update-like request which never receives any real file deltas
   2             repos.status(rev, null, SVNDepth.INFINITY, reporter, editor);

after the method returns we can look at the collected properties:

   1             //now iterate over file and directory properties and print them out to the console
   2             Map dirProps = editor.getDirsToProps();
   3             for (Iterator dirPathsIter = dirProps.keySet().iterator(); dirPathsIter.hasNext();) {
   4                 String path = (String) dirPathsIter.next();
   5                 Map props = (Map) dirProps.get(path);
   6                 System.out.println("Directory '" + path + "' has the following properties:");
   7                 for (Iterator propNamesIter = props.keySet().iterator(); propNamesIter.hasNext();) {
   8                     String propName = (String) propNamesIter.next();
   9                     SVNPropertyValue propValue = (SVNPropertyValue) props.get(propName);
  10                     System.out.println("  '" + propName + "' = '" + SVNPropertyValue.getPropertyAsString(propValue) + "'");
  11                 }
  12                 System.out.println();
  13             }
  14 
  15             Map fileProps = editor.getFilesToProps();
  16             for (Iterator filePathsIter = fileProps.keySet().iterator(); filePathsIter.hasNext();) {
  17                 String path = (String) filePathsIter.next();
  18                 Map props = (Map) fileProps.get(path);
  19                 System.out.println("File '" + path + "' has the following properties:");
  20                 for (Iterator propNamesIter = props.keySet().iterator(); propNamesIter.hasNext();) {
  21                     String propName = (String) propNamesIter.next();
  22                     SVNPropertyValue propValue = (SVNPropertyValue) props.get(propName);
  23                     System.out.println("  '" + propName + "' = '" + SVNPropertyValue.getPropertyAsString(propValue) + "'");
  24                 }
  25                 System.out.println();
  26             }

You can look at the entire source code in Recursively fetching properties from a repository in a single request.

Recursively fetching properties from a repository (low-level API) (last edited 2008-09-05 18:59:11 by 194)