[jcifs] Performance improvement

Johan Hägre johan at hagre.net
Thu Dec 20 16:26:55 MST 2012


Hello,

I have recently started using jcifs-1.3.17 to add support for direct 
access to SMB shares in an old web application I have used for years, it 
used to read the files from the local filesystem. When I replaced the 
regular File objects with SmbFile objects and started the application 
the performance was horrible, what used to take a second took several 
minutes (loading the start page). After a week or so of investigating 
the problem I have found the cause, it seems that the equals() and 
hashCode() methods of SmbFile are quite slow. My application caches 
folder settings in a HashMap using the SmbFile objects as keys so it was 
heavily affected by this. By overriding the mentioned methods the 
performance is about the same as when using the local file system, my 
implementation looks like this.

     @Override
     public int hashCode() {
         return getPath().hashCode();
     }

     @Override
     public boolean equals(Object pObj) {
         if (pObj == null) {
             return false;
         }
         try {
             return getPath().equals(((SmbFileImpl) pObj).getPath());
         } catch (ClassCastException e) {
             return false;
         }
     }

This implementation is not as fault tolerant for errors in the URL as 
the original one so I have also added a check to the end of each 
constructor to make sure the URLs are OK.

     private void verifyPath() throws SmbException {
         String vPath = getPath();
         if (!vPath.toLowerCase().startsWith("smb://")) {
             throw new SMBPathFaultException("An SMB URL must start with 
'smb://'");
         }
         if (vPath.indexOf("//", "smb://".length()) != -1)  {
             throw new SMBPathFaultException("An SMB URL must not 
contain '//' except from in the beginning");
         }
         if (isDirectory()) {
             if (!vPath.endsWith("/")) {
                 throw new SMBPathFaultException("A directory path must 
end with a '/'");
             }
         } else {
             if (vPath.endsWith("/")) {
                 throw new SMBPathFaultException("A regular file path 
must not end with a '/'");
             }
         }
     }

Now to my question, the code seems to work OK and the performance is 
clearly a lot better (I measured the equals method to take about 30ms on 
my laptop before, now it's less than 1ms). But since I'm no expert on 
either the jcifs code or the SMB protocol it would be great if someone 
with more knowledge took a look at the problem and either solved it in a 
better way or if my solution is OK simply included my code in a coming 
release.


Regards
Johan Hägre


More information about the jCIFS mailing list