optimisation: way to get file boolean attributes in batch
authorAlexey Kudravtsev <cdr@intellij.com>
Fri, 27 Jan 2012 15:39:30 +0000 (19:39 +0400)
committerAlexey Kudravtsev <cdr@intellij.com>
Mon, 30 Jan 2012 06:21:18 +0000 (10:21 +0400)
13 files changed:
platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java
platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFileSystem.java
platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java
platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java
platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java
platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/FileInfo.java
platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32Kernel.java
platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32LocalFileSystem.java
platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java
platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java
platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java
platform/testFramework/src/com/intellij/mock/MockLocalFileSystem.java
platform/util/src/com/intellij/openapi/util/io/FileUtil.java

index 4a8e7f0a0e0713ec2ca3303a426c771b255b640a..c64a109153a774108a033fbc712b42a4509412a9 100644 (file)
@@ -215,11 +215,12 @@ public class PsiDirectoryImpl extends PsiElementBase implements PsiDirectory, Qu
     ProgressIndicatorProvider.checkCanceled();
 
     for (VirtualFile vFile : myFile.getChildren()) {
+      boolean isDir = vFile.isDirectory();
       if (processor instanceof PsiFileSystemItemProcessor &&
-          !((PsiFileSystemItemProcessor)processor).acceptItem(vFile.getName(), vFile.isDirectory())) {
+          !((PsiFileSystemItemProcessor)processor).acceptItem(vFile.getName(), isDir)) {
         continue;
       }
-      if (vFile.isDirectory()) {
+      if (isDir) {
         PsiDirectory dir = myManager.findDirectory(vFile);
         if (dir != null) {
           if (!processor.execute(dir)) return false;
index d0ebd6f159fbb74a116f68b228fe8c86ef755758..f2ba971539121772b2f773ecacb12ae1cc3b9b12 100644 (file)
@@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileListener;
 import com.intellij.openapi.vfs.VirtualFileManager;
 import com.intellij.openapi.vfs.VirtualFileSystem;
+import org.intellij.lang.annotations.MagicConstant;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -103,4 +104,48 @@ public abstract class NewVirtualFileSystem extends VirtualFileSystem implements
   public String getCanonicallyCasedName(@NotNull VirtualFile file) {
     return file.getName();
   }
+
+  public static final int BA_EXISTS    = 0x01;
+  public static final int BA_REGULAR   = 0x02;
+  public static final int BA_DIRECTORY = 0x04;
+  public static final int BA_HIDDEN    = 0x08;
+
+  @MagicConstant(flags = {BA_EXISTS, BA_REGULAR, BA_DIRECTORY, BA_HIDDEN})
+  public @interface FileBooleanAttributes {}
+
+  /**
+   * Queries the file about several attributes at once, and returns them ORed together.
+   * This method is typically faster than several methods calls querying corresponding file attributes one by one.
+   *
+   * @param file  to query.
+   * @param flags Attributes to query the file for.
+   *              Each attribute is an int constant from this class.
+   *              Following attributes are defined:
+   *              <ul>
+   *              <li>{@link #BA_EXISTS} is set if {@link java.io.File#exists()} returns true</li>
+   *              <li>{@link #BA_DIRECTORY} is set if {@link java.io.File#isDirectory()} returns true</li>
+   *              <li>{@link #BA_HIDDEN} is set if {@link java.io.File#isHidden()} returns true</li>
+   *              <li>{@link #BA_REGULAR} is set if {@link java.io.File#isFile()} returns true</li>
+   *              </ul>
+   *              Attributes can be bitwise ORed together to query several file attributes at once.
+   *              <code>-1</code> as an argument value will query all attributes.
+   * @return Attributes mask for the file, where the bit is set if the corresponding attribute for the file is true.
+   *         That is, the return value is <pre>{@code
+   *           (file.exists() ? BA_EXISTS : 0) |
+   *           (file.isDirectory()() ? BA_DIRECTORY : 0) |
+   *           (file.isRegular()() ? BA_REGULAR : 0) |
+   *           (file.isHidden()() ? BA_HIDDEN : 0)
+   *           }</pre>
+   *         Except that the bit in the return value is undefined if the corresponding bit in the flags parameter is not set.
+   *  <p>
+   *  Example usage:
+   *  <pre>{@code
+   *  int attributes = getBooleanAttributes(file, BA_EXISTS | BA_DIRECTORY);
+   *  if ((attributes & BA_EXISTS) != 0) {
+   *    // file exists
+   *    boolean isDirectory = (attributes & BA_DIRECTORY) != 0;
+   *  }}</pre>
+   */
+  @FileBooleanAttributes
+  public abstract int getBooleanAttributes(@NotNull final VirtualFile file, @FileBooleanAttributes int flags);
 }
index b2688f67df36f2e0963159224335dd0bbcd3a22e..7f35b77eba8c4431e26d56a8aa239605c0c9f6d7 100644 (file)
@@ -270,7 +270,7 @@ public class TempFileSystem extends NewVirtualFileSystem {
     }
   }
 
-  private static abstract class FSItem {
+  private abstract static class FSItem {
     private final FSDir myParent;
     private String myName;
     private long myTimestamp;
@@ -365,4 +365,13 @@ public class TempFileSystem extends NewVirtualFileSystem {
       return false;
     }
   }
+
+  @Override
+  public int getBooleanAttributes(@NotNull VirtualFile file, int flags) {
+    FSItem item = convert(file);
+    int isDir = item instanceof FSDir ? BA_DIRECTORY : 0;
+    int exists = item == null ? 0 : BA_EXISTS;
+    int regular = isDir == 0 ? BA_REGULAR : 0;
+    return isDir | exists | regular;
+  }
 }
index 66d5eb272da9cb21459ae82a0d80d967f9f56956..abaac61050f4325423b964e3067fb71bf1f31c36 100644 (file)
@@ -365,4 +365,22 @@ public class JarFileSystemImpl extends JarFileSystem implements ApplicationCompo
   public VirtualFile refreshAndFindFileByPath(@NotNull String path) {
     return VfsImplUtil.refreshAndFindFileByPath(this, path);
   }
+
+  @Override
+  public int getBooleanAttributes(@NotNull VirtualFile file, int flags) {
+    int exists = 0;
+    JarHandler handler = getHandler(file);
+    if ((flags & BA_EXISTS) != 0) {
+      exists = handler.exists(file) ? BA_EXISTS : 0;
+    }
+    int isDir = 0;
+    if ((flags & BA_DIRECTORY) != 0) {
+      isDir = handler.isDirectory(file) ? BA_DIRECTORY : 0;
+    }
+    int regular = 0;
+    if ((flags & BA_REGULAR) != 0) {
+      regular = isDir == 0 ? BA_REGULAR : 0;
+    }
+    return exists | isDir | regular;
+  }
 }
index 915ca59e82b805771a3ef388b06d04d815f6b819..f727a8e7278feb18aee939fa85f069f3af755fca 100644 (file)
@@ -25,10 +25,7 @@ import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.*;
 import com.intellij.openapi.vfs.ex.VirtualFileManagerEx;
-import com.intellij.openapi.vfs.newvfs.ManagingFS;
-import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
-import com.intellij.openapi.vfs.newvfs.RefreshQueue;
-import com.intellij.openapi.vfs.newvfs.VfsImplUtil;
+import com.intellij.openapi.vfs.newvfs.*;
 import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile;
 import com.intellij.util.ArrayUtil;
 import com.intellij.util.Processor;
@@ -140,10 +137,6 @@ public abstract class LocalFileSystemBase extends LocalFileSystem {
   private static final Method JAVA_IO_FILESYSTEM_GET_BOOLEAN_ATTRIBUTES_METHOD;
   private static final Object/* java.io.FileSystem */ JAVA_IO_FILESYSTEM;
   // copied from FileSystem
-  private static final int BA_EXISTS    = 0x01;
-  private static final int BA_REGULAR   = 0x02;
-  private static final int BA_DIRECTORY = 0x04;
-  private static final int BA_HIDDEN    = 0x08;
 
   static {
     Object fs;
@@ -170,6 +163,8 @@ public abstract class LocalFileSystemBase extends LocalFileSystem {
     JAVA_IO_FILESYSTEM_GET_BOOLEAN_ATTRIBUTES_METHOD = getBooleanAttributes;
   }
 
+
+
   @NotNull
   private static File convertToIOFileAndCheck(@NotNull final VirtualFile file) throws FileNotFoundException {
     final File ioFile = convertToIOFile(file);
@@ -769,6 +764,17 @@ public abstract class LocalFileSystemBase extends LocalFileSystem {
     }
   }
 
+  @Override
+  public int getBooleanAttributes(@NotNull VirtualFile file, int flags) {
+    int attributes = getBooleanAttributes(convertToIOFile(file));
+    if (attributes != -1) return attributes & flags;
+    return ((flags & BA_EXISTS) != 0 && exists(file) ? BA_EXISTS : 0) |
+           ((flags & BA_DIRECTORY) != 0 && isDirectory(file) ? BA_DIRECTORY : 0) |
+           ((flags & BA_REGULAR) != 0 && !isSpecialFile(file) ? BA_REGULAR : 0) |
+           ((flags & BA_HIDDEN) != 0 && convertToIOFile(file).isHidden() ? BA_HIDDEN : 0)
+      ;
+  }
+
   @Override
   public void refresh(final boolean asynchronous) {
     RefreshQueue.getInstance().refresh(asynchronous, true, null, ManagingFS.getInstance().getRoots(this));
index ea85f580259fc5cab838e246845b7e85167aa34b..52cdc416ac7fa0af15fd7a1a7096fcf05c7e2e11 100644 (file)
  */
 package com.intellij.openapi.vfs.impl.win32;
 
+import org.intellij.lang.annotations.MagicConstant;
+
 /**
  * @author Dmitry Avdeev
  */
 public class FileInfo {
 
-    static {
-        initIDs();
-    }
+  static {
+    initIDs();
+  }
+
+  private static native void initIDs();
+
+  public String name;
+
+  @MagicConstant(flagsFromClass = Win32Kernel.class)
+  public int attributes;
 
-    private static native void initIDs();
-    
-    public String name;
-    public int attributes;
-    public long timestamp;
-    public long length;
+  public long timestamp;
+  public long length;
 
-    public String toString() {
-        return name;
-    }
+  public String toString() {
+    return name;
+  }
 }
index c7fe8b9b2706d676c9619030843a3fbe7599cff3..18450eb9ea6c55ab25f9372b441423bb5c2b9797 100644 (file)
  */
 package com.intellij.openapi.vfs.impl.win32;
 
+import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem;
 import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
@@ -27,7 +30,10 @@ import java.util.Map;
  */
 public class Win32Kernel {
   public static final int FILE_ATTRIBUTE_READONLY = 0x0001;
+  public static final int FILE_ATTRIBUTE_HIDDEN = 0x0002;
   public static final int FILE_ATTRIBUTE_DIRECTORY = 0x0010;
+  public static final int FILE_ATTRIBUTE_DEVICE = 0x0040;
+  public static final int FILE_ATTRIBUTE_REPARSE_POINT = 0x0400;
 
   private final IdeaWin32 myKernel = new IdeaWin32();
 
@@ -43,13 +49,12 @@ public class Win32Kernel {
       return ArrayUtil.EMPTY_STRING_ARRAY;
     }
     ArrayList<String> names = new ArrayList<String>(fileInfos.length);
-    for (int i = 0, fileInfosLength = fileInfos.length; i < fileInfosLength; i++) {
-      FileInfo info = fileInfos[i];
+    for (FileInfo info : fileInfos) {
       if (info.name.equals(".")) {
         myCache.put(absolutePath, info);
         continue;
       }
-      else if (info.name.equals("..")) {
+      if (info.name.equals("..")) {
         continue;
       }
       myCache.put(absolutePath + "/" + info.name, info);
@@ -59,8 +64,8 @@ public class Win32Kernel {
     return ArrayUtil.toStringArray(names);
   }
 
-  public void exists(String path) throws FileNotFoundException {
-    getInfo(path);
+  public boolean exists(String path) {
+    return doGetInfo(path) != null;
   }
 
   public boolean isDirectory(String path) throws FileNotFoundException {
@@ -84,14 +89,42 @@ public class Win32Kernel {
   }
 
   private FileInfo getInfo(String path) throws FileNotFoundException {
+    FileInfo info = doGetInfo(path);
+    if (info == null) {
+      throw new FileNotFoundException(path);
+    }
+    return info;
+  }
+
+  @Nullable
+  private FileInfo doGetInfo(String path) {
     FileInfo info = myCache.get(path);
     if (info == null) {
       info = myKernel.getInfo(path.replace('/', '\\'));
       if (info == null) {
-        throw new FileNotFoundException(path);
+        return null;
       }
       myCache.put(path, info);
     }
     return info;
   }
+
+  @NewVirtualFileSystem.FileBooleanAttributes
+  public int getBooleanAttributes(@NotNull String path, @NewVirtualFileSystem.FileBooleanAttributes int flags) {
+    FileInfo info = doGetInfo(path);
+    int result = 0;
+    if ((flags & NewVirtualFileSystem.BA_EXISTS) != 0) {
+      result |= info == null ? 0 : NewVirtualFileSystem.BA_EXISTS;
+    }
+    if ((flags & NewVirtualFileSystem.BA_DIRECTORY) != 0) {
+      result |= info == null || (info.attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ? 0 : NewVirtualFileSystem.BA_DIRECTORY;
+    }
+    if ((flags & NewVirtualFileSystem.BA_REGULAR) != 0) {
+      result |= info == null || (info.attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0 ? 0 : NewVirtualFileSystem.BA_REGULAR;
+    }
+    if ((flags & NewVirtualFileSystem.BA_HIDDEN) != 0) {
+      result |= info == null || (info.attributes & FILE_ATTRIBUTE_HIDDEN) == 0 ? 0 : NewVirtualFileSystem.BA_HIDDEN;
+    }
+    return result;
+  }
 }
index 126b8505ebe45d34f0a61266e93f88b66330b901..c69ca7f5379c5bf4110e130dff05d8051e65acb1 100644 (file)
@@ -33,33 +33,34 @@ import java.util.Set;
 public class Win32LocalFileSystem extends LocalFileSystemBase {
   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.impl.win32.Win32LocalFileSystem");
 
-  private static boolean ourIsAvailable;
+  private static final boolean ourIsAvailable;
 
   static {
+    boolean available = false;
     if (SystemInfo.isWindows) {
       String libName = SystemInfo.is64Bit ? "IdeaWin64" : "IdeaWin32";
       try {
         System.load(PathManager.getHomePath() + "/community/bin/win/" + libName + ".dll");
-        ourIsAvailable = true;
+        available = true;
       }
       catch (Throwable t0) {
         try {
           System.load(PathManager.getHomePath() + "/bin/win/" + libName + ".dll");
-          ourIsAvailable = true;
+          available = true;
         }
         catch (Throwable t1) {
           try {
             System.loadLibrary(libName);
-            ourIsAvailable = true;
+            available = true;
           }
           catch (Throwable t2) {
             LOG.warn("Failed to load native filesystem for Windows", t2);
-            ourIsAvailable = false;
           }
         }
       }
     }
-    if (ourIsAvailable) {
+    ourIsAvailable = available;
+    if (available) {
       LOG.info("Native filesystem for Windows is operational");
     }
   }
@@ -108,16 +109,11 @@ public class Win32LocalFileSystem extends LocalFileSystemBase {
   @Override
   public boolean exists(@NotNull VirtualFile fileOrDirectory) {
     if (fileOrDirectory.getParent() == null) return true;
-    try {
-      myKernel.exists(fileOrDirectory.getPath());
-      if (checkMe && !super.exists(fileOrDirectory)) {
-        LOG.error(fileOrDirectory.getPath());
-      }
-      return true;
-    }
-    catch (FileNotFoundException e) {
-      return super.exists(fileOrDirectory);
+    boolean b = myKernel.exists(fileOrDirectory.getPath());
+    if (checkMe && b != super.exists(fileOrDirectory)) {
+      LOG.error(fileOrDirectory.getPath());
     }
+    return b;
   }
 
   @Override
@@ -196,4 +192,9 @@ public class Win32LocalFileSystem extends LocalFileSystemBase {
   public void removeWatchedRoot(@NotNull WatchRequest watchRequest) {
     throw new UnsupportedOperationException();
   }
+
+  @Override
+  public int getBooleanAttributes(@NotNull VirtualFile file, int flags) {
+    return myKernel.getBooleanAttributes(file.getPath(), flags);
+  }
 }
index 4e8508153bedca4462d0cf916f82b6592010751f..6ff87f199cb17e797204e06708bdd97c8b124f0c 100644 (file)
@@ -42,6 +42,7 @@ import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent;
 import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
 import com.intellij.util.ArrayUtil;
 import com.intellij.util.PathUtil;
+import com.intellij.util.SmartList;
 import com.intellij.util.SystemProperties;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.text.CaseInsensitiveStringHashingStrategy;
@@ -312,14 +313,15 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
     return VfsUtil.toVirtualFileArray(roots);
   }
 
-
   @Nullable
   private VirtualFileSystemEntry createAndFindChildWithEventFire(@NotNull String name) {
     final NewVirtualFileSystem delegate = getFileSystem();
     VirtualFile fake = new FakeVirtualFile(this, name);
-    if (delegate.exists(fake)) {
+    int attributes = delegate.getBooleanAttributes(fake, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY);
+    if ((attributes & NewVirtualFileSystem.BA_EXISTS) != 0) {
       final String realName = delegate.getCanonicallyCasedName(fake);
-      VFileCreateEvent event = new VFileCreateEvent(null, this, realName, delegate.isDirectory(fake), true);
+      boolean isDir = (attributes & NewVirtualFileSystem.BA_DIRECTORY) != 0;
+      VFileCreateEvent event = new VFileCreateEvent(null, this, realName, isDir, true);
       RefreshQueue.getInstance().processSingleEvent(event);
       return findChild(realName);
     }
@@ -526,14 +528,16 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
     final Map<String, VirtualFileSystemEntry> map = asMap();
     if (map == null) return Collections.emptyList();
 
-    List<String> names = new ArrayList<String>();
+    List<String> names = null;
+
     for (Map.Entry<String, VirtualFileSystemEntry> entry : map.entrySet()) {
       if (entry.getValue() == NULL_VIRTUAL_FILE) {
+        if (names == null) names = new SmartList<String>();
         names.add(entry.getKey());
       }
     }
 
-    return names;
+    return names == null ? Collections.<String>emptyList() : names;
   }
 
   @Override
index 9a2de59babeb64bdbe7169f5de7e40ae80fd9a60..0d387162d9fc580a495340f407599440c6daa774 100644 (file)
@@ -48,6 +48,7 @@ import gnu.trove.TIntObjectHashMap;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
 
 import java.io.*;
 import java.util.*;
@@ -189,7 +190,8 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
         childrenIds[i] = currentIds[idx];
       }
       else {
-        int childId = createAndCopyRecord(delegate, new FakeVirtualFile(file, name), id);
+        FakeVirtualFile child = new FakeVirtualFile(file, name);
+        int childId = createAndCopyRecord(delegate, child, id, delegate.isDirectory(child));
         childrenIds[i] = childId;
       }
     }
@@ -283,12 +285,16 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
     return FSRecords.getModCount();
   }
 
-  private static boolean copyRecordFromDelegateFS(final int id, final int parentId, final VirtualFile file, NewVirtualFileSystem delegate) {
+  private static boolean copyRecordFromDelegateFS(final int id,
+                                                  final int parentId,
+                                                  final VirtualFile file,
+                                                  NewVirtualFileSystem delegate,
+                                                  boolean isDir) {
     String name = file.getName();
 
-    if (name.length() > 0 && namesEqual(delegate, name, FSRecords.getName(id))) return false; // TODO: Handle root attributes change.
+    if (!name.isEmpty() && namesEqual(delegate, name, FSRecords.getName(id))) return false; // TODO: Handle root attributes change.
 
-    if (name.length() == 0) {            // TODO: hack
+    if (name.isEmpty()) {            // TODO: hack
       if (areChildrenLoaded(id)) return false;
     }
 
@@ -299,11 +305,9 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
 
     FSRecords.setTimestamp(id, delegate.getTimeStamp(file));
 
-    boolean directory = delegate.isDirectory(file);
+    FSRecords.setLength(id, isDir ? -1L : delegate.getLength(file));
 
-    FSRecords.setLength(id, directory ? -1L : delegate.getLength(file));
-
-    FSRecords.setFlags(id, (directory ? IS_DIRECTORY_FLAG : 0) |
+    FSRecords.setFlags(id, (isDir ? IS_DIRECTORY_FLAG : 0) |
                            (delegate.isWritable(file) ? 0 : IS_READ_ONLY) |
                            (delegate.isSymLink(file) ? IS_SYMLINK : 0) |
                            (delegate.isSpecialFile(file) ? IS_SPECIAL : 0), true);
@@ -398,8 +402,10 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
     }
 
     VirtualFile fake = new FakeVirtualFile(parent, childName);
-    if (delegate.exists(fake)) {
-      int child = createAndCopyRecord(delegate, fake, parentId);
+    int attributes = delegate.getBooleanAttributes(fake, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY);
+    if ((attributes & NewVirtualFileSystem.BA_EXISTS) != 0) {
+      boolean isDir = (attributes & NewVirtualFileSystem.BA_DIRECTORY) != 0;
+      int child = createAndCopyRecord(delegate, fake, parentId, isDir);
       FSRecords.updateList(parentId, ArrayUtil.append(children, child));
       return child;
     }
@@ -722,13 +728,13 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
     synchronized (LOCK) {
       final String rootUrl = fs.getProtocol() + "://" + basePath;
       VirtualFileSystemEntry root = myRoots.get(rootUrl);
-      if (root == null && basePath.length() == 0) {
+      if (root == null && basePath.isEmpty()) {
         root = myFakeRoot;
       }
       if (root == null) {
         try {
           final int rootId = FSRecords.findRootRecord(rootUrl);
-          if (basePath.length() > 0) {
+          if (!basePath.isEmpty()) {
             root = new VirtualDirectoryImpl(basePath, null, fs, rootId) {
               @NotNull
               @Override
@@ -756,14 +762,14 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
 
               @Override
               public VirtualFileSystemEntry findChild(@NotNull String name) {
-                if (name.length() == 0) return null;
+                if (name.isEmpty()) return null;
                 return findRoot(name, fs);
               }
             };
           }
           if (!fs.exists(root)) return null;
 
-          boolean newRoot = copyRecordFromDelegateFS(rootId, 0, root, fs);
+          boolean newRoot = copyRecordFromDelegateFS(rootId, 0, root, fs, true);
           if (!newRoot) {
             if (fs.getTimeStamp(root) != FSRecords.getTimestamp(rootId)) {
               root.markDirtyRecursively();
@@ -774,7 +780,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
           throw new RuntimeException(e);
         }
 
-        if (basePath.length() > 0) {
+        if (!basePath.isEmpty()) {
           myRoots.put(rootUrl, root);
           myRootsById.put(root.getId(), root);
         }
@@ -949,10 +955,12 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
 
   private static void executeCreateChild(final VirtualFile parent, final String name) {
     final NewVirtualFileSystem delegate = getDelegate(parent);
-    VirtualFile fakeFile = new FakeVirtualFile(parent, name);
-    if (delegate.exists(fakeFile)) {
+    VirtualFile fake = new FakeVirtualFile(parent, name);
+    int attributes = delegate.getBooleanAttributes(fake, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY);
+    if ((attributes & NewVirtualFileSystem.BA_EXISTS) != 0) {
       final int parentId = getFileId(parent);
-      int childId = createAndCopyRecord(delegate, fakeFile, parentId);
+      boolean isDir = (attributes & NewVirtualFileSystem.BA_DIRECTORY) != 0;
+      int childId = createAndCopyRecord(delegate, fake, parentId, isDir);
 
       appendIdToParentList(parentId, childId);
       final VirtualDirectoryImpl dir = (VirtualDirectoryImpl)parent;
@@ -960,9 +968,9 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
     }
   }
 
-  private static int createAndCopyRecord(NewVirtualFileSystem delegateSystem, VirtualFile delegateFile, int parentId) {
+  private static int createAndCopyRecord(NewVirtualFileSystem delegateSystem, VirtualFile delegateFile, int parentId, boolean isDir) {
     int childId = FSRecords.createRecord();
-    copyRecordFromDelegateFS(childId, parentId, delegateFile, delegateSystem);
+    copyRecordFromDelegateFS(childId, parentId, delegateFile, delegateSystem, isDir);
     return childId;
   }
 
@@ -1067,7 +1075,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
     FSRecords.setLength(getFileId(file), delegate.getLength(file));
     FSRecords.setTimestamp(getFileId(file), delegate.getTimeStamp(file));
 
-    ((NewVirtualFile)file).setModificationStamp(newModificationStamp);
+    ((VirtualFileSystemEntry)file).setModificationStamp(newModificationStamp);
   }
 
   @SuppressWarnings({"UnusedDeclaration"})
@@ -1092,6 +1100,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
     return FSRecords.getName(id);
   }
 
+  @TestOnly
   public void cleanPersistedContents() {
     try {
       final int[] roots = FSRecords.listRoots();
@@ -1104,6 +1113,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
     }
   }
 
+  @TestOnly
   private static void cleanPersistedContentsRecursively(int id) {
     if (isDirectory(id)) {
       for (int child : FSRecords.list(id)) {
@@ -1116,11 +1126,12 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
   }
 
   public static NewVirtualFileSystem replaceWithNativeFS(NewVirtualFileSystem delegate) {
-    if (delegate.getProtocol().equals(LocalFileSystem.PROTOCOL) && Registry.is("filesystem.useNative")) {
-        if (SystemInfo.isWindows && Win32LocalFileSystem.isAvailable()) {
-          delegate = Win32LocalFileSystem.getWin32Instance();
-        }
-      }
+    if (delegate.getProtocol().equals(LocalFileSystem.PROTOCOL) &&
+        Registry.is("filesystem.useNative") &&
+        SystemInfo.isWindows &&
+        Win32LocalFileSystem.isAvailable()) {
+      delegate = Win32LocalFileSystem.getWin32Instance();
+    }
     return delegate;
   }
 }
index 39f9da022ab9bc7c22355d3d0682697a794505b0..9360c401f53d93b6813dababd5c890054cf881ce 100644 (file)
@@ -25,6 +25,7 @@ import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile;
 import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
 import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
 import com.intellij.util.containers.Queue;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.*;
 
@@ -47,12 +48,15 @@ public class RefreshWorker {
   public void scan() {
     final NewVirtualFile root = (NewVirtualFile)myRefreshRoot;
     NewVirtualFileSystem delegate = root.getFileSystem();
-    if (root.isDirty() && !delegate.exists(root)) {
+    int attributes = delegate.getBooleanAttributes(root, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY);
+
+    if (root.isDirty() && (attributes & NewVirtualFileSystem.BA_EXISTS) == 0) {
       scheduleDeletion(root);
       root.markClean();
     }
     else {
-      if (root.isDirectory()) {
+      boolean isDir = (attributes & NewVirtualFileSystem.BA_DIRECTORY) != 0;
+      if (isDir) {
         delegate = PersistentFS.replaceWithNativeFS(delegate);
       }
 
@@ -86,14 +90,16 @@ public class RefreshWorker {
 
             for (VirtualFile child : file.getChildren()) {
               if (!deletedNames.contains(child.getName())) {
-                scheduleChildRefresh(file, child, delegate);
+                int childAttributes = delegate.getBooleanAttributes(child, -1);
+                scheduleChildRefresh(file, child, delegate, childAttributes);
               }
             }
           }
           else {
             for (VirtualFile child : file.getCachedChildren()) {
-              if (delegate.exists(child)) {
-                scheduleChildRefresh(file, child, delegate);
+              int childAttributes = delegate.getBooleanAttributes(child, -1);
+              if ((childAttributes & NewVirtualFileSystem.BA_EXISTS) != 0) {
+                scheduleChildRefresh(file, child, delegate, childAttributes);
               }
               else {
                 scheduleDeletion(child);
@@ -102,11 +108,13 @@ public class RefreshWorker {
 
             final List<String> names = dir.getSuspiciousNames();
             for (String name : names) {
-              if (name.length() == 0) continue;
+              if (name.isEmpty()) continue;
 
               final VirtualFile fake = new FakeVirtualFile(file, name);
-              if (delegate.exists(fake)) {
-                scheduleCreation(file, name, delegate.isDirectory(fake));
+              int attrs = delegate.getBooleanAttributes(fake, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY);
+              if ((attrs & NewVirtualFileSystem.BA_EXISTS) != 0) {
+                boolean isDira = (attrs & NewVirtualFileSystem.BA_DIRECTORY) != 0;
+                scheduleCreation(file, name, isDira);
               }
             }
           }
@@ -132,13 +140,16 @@ public class RefreshWorker {
     }
   }
 
-  private void scheduleChildRefresh(final VirtualFileSystemEntry file, final VirtualFile child, final NewVirtualFileSystem delegate) {
+  private void scheduleChildRefresh(@NotNull VirtualFileSystemEntry file,
+                                    @NotNull VirtualFile child,
+                                    @NotNull NewVirtualFileSystem delegate,
+                                    @NewVirtualFileSystem.FileBooleanAttributes int childAttributes) {
     final boolean currentIsDirectory = child.isDirectory();
     final boolean currentIsSymlink = child.isSymLink();
     final boolean currentIsSpecial = child.isSpecialFile();
-    final boolean upToDateIsDirectory = delegate.isDirectory(child);
+    final boolean upToDateIsDirectory = (childAttributes & NewVirtualFileSystem.BA_DIRECTORY) != 0;
     final boolean upToDateIsSymlink = delegate.isSymLink(child);
-    final boolean upToDateIsSpecial = delegate.isSpecialFile(child);
+    final boolean upToDateIsSpecial = (childAttributes & (NewVirtualFileSystem.BA_REGULAR | NewVirtualFileSystem.BA_DIRECTORY | NewVirtualFileSystem.BA_EXISTS)) == NewVirtualFileSystem.BA_EXISTS;
     if (currentIsDirectory != upToDateIsDirectory || currentIsSymlink != upToDateIsSymlink || currentIsSpecial != upToDateIsSpecial) {
       scheduleDeletion(child);
       scheduleReCreation(file, child.getName(), upToDateIsDirectory);
index 4fb4e59373628b68f96827e814edadda2e1371f5..59be016ec53c326c147e5c7cd1184af2eed8f79d 100644 (file)
@@ -251,4 +251,9 @@ public class MockLocalFileSystem extends LocalFileSystem {
   public int getRank() {
     return 1;
   }
+
+  @Override
+  public int getBooleanAttributes(@NotNull VirtualFile file, int flags) {
+    return 0;
+  }
 }
index 3ed50898fc01098a91da1e9c31bdf0bf2b26f4d0..c48b53e30bdced41ee1714a21950d1db72a39c86 100644 (file)
@@ -41,7 +41,7 @@ import java.util.regex.Pattern;
 @SuppressWarnings({"UtilityClassWithoutPrivateConstructor"})
 public class FileUtil {
   public static final int MEGABYTE = 1024 * 1024;
-  public static final String ASYNC_DELETE_EXTENSION = ".__del__";
+  @NonNls public static final String ASYNC_DELETE_EXTENSION = ".__del__";
 
   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileUtil");
 
@@ -681,7 +681,7 @@ public class FileUtil {
       final int oldPermissions = FileSystemUtil.getPermissions(fromFile);
       final int newPermissions = FileSystemUtil.getPermissions(toFile);
       if (oldPermissions != -1 && newPermissions != -1) {
-        FileSystemUtil.setPermissions(toFile, (oldPermissions | newPermissions));
+        FileSystemUtil.setPermissions(toFile, oldPermissions | newPermissions);
       }
     }
   }
@@ -713,7 +713,7 @@ public class FileUtil {
   public static void copyDir(@NotNull File fromDir, @NotNull File toDir, boolean copySystemFiles) throws IOException {
     copyDir(fromDir, toDir, copySystemFiles ? null : new FileFilter() {
       public boolean accept(File file) {
-        return !file.getName().startsWith(".");
+        return !StringUtil.startsWithChar(file.getName(), '.');
       }
     });
   }
@@ -939,7 +939,7 @@ public class FileUtil {
     final StringBuilder builder = new StringBuilder(antPattern.length());
     int asteriskCount = 0;
     boolean recursive = true;
-    final int start = ignoreStartingSlash && (antPattern.startsWith("/") || antPattern.startsWith("\\")) ? 1 : 0;
+    final int start = ignoreStartingSlash && (StringUtil.startsWithChar(antPattern, '/') || StringUtil.startsWithChar(antPattern, '\\')) ? 1 : 0;
     for (int idx = start; idx < antPattern.length(); idx++) {
       final char ch = antPattern.charAt(idx);