virtual file pointers data race

This commit is contained in:
Alexey Kudravtsev
2010-12-30 15:25:16 +03:00
parent bfca5f972a
commit f942ca2bd1
7 changed files with 367 additions and 230 deletions
@@ -1,21 +1,27 @@
package com.intellij.openapi.vfs;
import com.intellij.concurrency.JobUtil;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.impl.VirtualFilePointerImpl;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.testFramework.IdeaTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
/**
* @author dsl
@@ -23,7 +29,13 @@ import java.util.ArrayList;
public class VirtualFilePointerTest extends IdeaTestCase {
private VirtualFilePointerManager myVirtualFilePointerManager;
static class LoggingListener implements VirtualFilePointerListener {
@Override
protected void setUp() throws Exception {
super.setUp();
myVirtualFilePointerManager = VirtualFilePointerManager.getInstance();
}
private static class LoggingListener implements VirtualFilePointerListener {
private final ArrayList<String> myLog = new ArrayList<String>();
@Override
@@ -100,7 +112,7 @@ public class VirtualFilePointerTest extends IdeaTestCase {
};
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run () {
public void run() {
VirtualFileManager.getInstance().refresh(false);
final VirtualFile virtualFile = getVirtualFile(tempDirectory);
virtualFile.refresh(false, true);
@@ -165,7 +177,7 @@ public class VirtualFilePointerTest extends IdeaTestCase {
};
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run () {
public void run() {
VirtualFileManager.getInstance().refresh(false);
final VirtualFile virtualFile = getVirtualFile(tempDirectory);
virtualFile.refresh(false, true);
@@ -392,9 +404,87 @@ public class VirtualFilePointerTest extends IdeaTestCase {
});
}
public void testThreads() throws IOException, InterruptedException {
final File ioTempDir = createTempDirectory();
final File ioPtrBase = new File(ioTempDir, "parent");
final File ioPtr = new File(ioPtrBase, "f1");
final File ioSand = new File(ioTempDir, "sand");
final File ioSandPtr = new File(ioSand, "f2");
ioSandPtr.getParentFile().mkdirs();
ioSandPtr.createNewFile();
ioPtr.getParentFile().mkdirs();
ioPtr.createNewFile();
doVfsRefresh();
final VirtualFilePointer pointer = createPointerByFile(ioPtr, null);
assertTrue(pointer.isValid());
final VirtualFile virtualFile = pointer.getFile();
assertNotNull(virtualFile);
assertTrue(virtualFile.isValid());
VirtualFileAdapter listener = new VirtualFileAdapter() {
@Override
public void fileCreated(VirtualFileEvent event) {
doit(pointer);
}
@Override
public void fileDeleted(VirtualFileEvent event) {
doit(pointer);
}
};
VirtualFileManager.getInstance().addVirtualFileListener(listener, getTestRootDisposable());
System.out.println("------------------");
for (int i=0;i<1000;i++) {
assertNotNull(pointer.getFile());
FileUtil.delete(ioPtrBase);
doVfsRefresh();
// ptr is now null, cached as map
final VirtualFile v = LocalFileSystem.getInstance().findFileByIoFile(ioSandPtr);
new WriteCommandAction.Simple(getProject()) {
@Override
protected void run() throws Throwable {
v.delete(this); //inc FS modCount
LocalFileSystem.getInstance().findFileByIoFile(ioSand).createChildData(this, ioSandPtr.getName());
}
}.execute().throwException();
// ptr is still null
assertTrue(ioPtrBase.mkdirs());
assertTrue(ioPtr.createNewFile());
doit(pointer);
doVfsRefresh();
}
}
private static void doit(final VirtualFilePointer pointer) {
if (((VirtualFilePointerImpl)pointer).isDisposed()) return;
boolean b = JobUtil.invokeConcurrentlyUnderProgress(Collections.nCopies(10, null), new Processor<Object>() {
@Override
public boolean process(Object o) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
VirtualFile file = pointer.getFile();
if (file != null && !file.isValid()) {
throw new IncorrectOperationException("I've caught it. I am that good");
}
}
});
return true;
}
}, false, null);
assertTrue(b);
}
@Override
protected void setUp() throws Exception {
super.setUp();
myVirtualFilePointerManager = VirtualFilePointerManager.getInstance();
protected boolean isRunInWriteAction() {
return false;
}
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.vfs.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
@@ -57,39 +58,41 @@ public class VirtualFilePointerImpl extends UserDataHolderBase implements Virtua
@NotNull
public String getFileName() {
update();
if (myFile != null) {
return myFile.getName();
Pair<VirtualFile, String> result = update();
VirtualFile file = result.first;
if (file != null) {
return file.getName();
}
int index = myUrl.lastIndexOf('/');
return index >= 0 ? myUrl.substring(index + 1) : myUrl;
String url = result.second;
int index = url.lastIndexOf('/');
return index >= 0 ? url.substring(index + 1) : url;
}
public VirtualFile getFile() {
checkDisposed();
update();
return myFile;
Pair<VirtualFile, String> result = update();
return result.first;
}
@NotNull
public String getUrl() {
//checkDisposed(); no check here since Disposer might want to compute hashcode during dispose()
update();
return getUrlNoUpdate();
Pair<VirtualFile, String> result = update();
return getUrlNoUpdate(result.first, result.second);
}
private String getUrlNoUpdate() {
return myUrl == null ? myFile.getUrl() : myUrl;
private static String getUrlNoUpdate(VirtualFile file, String url) {
return url == null ? file.getUrl() : url;
}
@NotNull
public String getPresentableUrl() {
checkDisposed();
update();
Pair<VirtualFile, String> result = update();
return PathUtil.toPresentableUrl(getUrl());
return PathUtil.toPresentableUrl(result.second);
}
private void checkDisposed() {
@@ -138,36 +141,42 @@ public class VirtualFilePointerImpl extends UserDataHolderBase implements Virtua
}
public boolean isValid() {
update();
return !disposed && myFile != null;
Pair<VirtualFile, String> result = update();
return !disposed && result.first != null;
}
void update() {
if (disposed) return;
Pair<VirtualFile, String> update() {
if (disposed) return null;
long lastUpdated = myLastUpdated;
String url = myUrl;
VirtualFile file = myFile;
long fsModCount = myVirtualFileManager.getModificationCount();
if (myLastUpdated == fsModCount) return;
myLastUpdated = fsModCount;
if (lastUpdated == fsModCount) return Pair.create(file, url);
if (myFile != null && !myFile.isValid()) {
myUrl = myFile.getUrl();
myFile = null;
if (file != null && !file.isValid()) {
url = file.getUrl();
file = null;
}
if (myFile == null) {
LOG.assertTrue(myUrl != null, "Both file & url are null");
myFile = myVirtualFileManager.findFileByUrl(myUrl);
if (myFile != null) {
myUrl = null;
if (file == null) {
LOG.assertTrue(url != null, "Both file & url are null");
file = myVirtualFileManager.findFileByUrl(url);
if (file != null) {
url = null;
}
}
else if (!myFile.exists()) {
myUrl = myFile.getUrl();
myFile = null;
if (file != null && !file.exists()) {
url = file.getUrl();
file = null;
}
myFile = file;
myUrl = url;
myLastUpdated = fsModCount;
return Pair.create(file, url);
}
@Override
public String toString() {
return getUrlNoUpdate();
return getUrlNoUpdate(myFile, myUrl);
}
public void dispose() {
@@ -178,9 +187,13 @@ public class VirtualFilePointerImpl extends UserDataHolderBase implements Virtua
if (TRACE_CREATION) {
putUserData(KILL_TRACE, new Throwable());
}
String url = getUrlNoUpdate();
String url = getUrlNoUpdate(myFile, myUrl);
disposed = true;
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(url, myListener);
}
}
public boolean isDisposed() {
return disposed;
}
}
@@ -332,9 +332,6 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
}
}
//if (myListenerToPointersMap.isEmpty()) {
// System.err.println("All pointers are disposed");
//}
synchronized (myContainers) {
if (!myContainers.isEmpty()) {
VirtualFilePointerContainerImpl container = myContainers.iterator().next();
@@ -20,11 +20,13 @@
package com.intellij.openapi.vfs.newvfs.impl;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
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.containers.ContainerUtil;
import com.intellij.util.text.CaseInsensitiveStringHashingStrategy;
@@ -41,9 +43,11 @@ import java.util.*;
public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
private final NewVirtualFileSystem myFS;
// guarded by this
private Object myChildren; // Either HashMap<String, VFile> or VFile[]
public VirtualDirectoryImpl(final String name, final VirtualDirectoryImpl parent, final NewVirtualFileSystem fs, final int id) {
public VirtualDirectoryImpl(@NotNull String name, final VirtualDirectoryImpl parent, @NotNull NewVirtualFileSystem fs, final int id) {
super(name, parent, id);
myFS = fs;
}
@@ -54,24 +58,34 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
}
@Nullable
private NewVirtualFile findChild(final String name, final boolean createIfNotFound, boolean ensureCanonicalName) {
final NewVirtualFile result = doFindChild(name, createIfNotFound, ensureCanonicalName);
synchronized (this) {
if (result == null && myChildren instanceof Map) {
ensureAsMap().put(name, NullVirtualFile.INSTANCE);
private NewVirtualFile findChild(@NotNull String name, final boolean createIfNotFound, boolean ensureCanonicalName) {
final VirtualFile result = doFindChild(name, createIfNotFound, ensureCanonicalName);
if (result == NullVirtualFile.INSTANCE) {
return createIfNotFound ? createAndFindChildWithEventFire(name) : null;
}
if (result == null) {
synchronized (this) {
Map<String, VirtualFile> map = asMap();
if (map != null) {
map.put(name, NullVirtualFile.INSTANCE);
}
}
}
return result;
return (NewVirtualFile)result;
}
@Nullable
private NewVirtualFile doFindChild(String name, final boolean createIfNotFound, boolean ensureCanonicalName) {
private VirtualFile doFindChild(@NotNull String name, final boolean createIfNotFound, boolean ensureCanonicalName) {
if (name.length() == 0) {
return null;
}
final VirtualFile[] a = asArray();
final VirtualFile[] a;
synchronized (this) {
a = asArray();
}
if (a != null) {
Object encoded = encodeName(name);
byte[] bytes = encoded instanceof byte[] ? (byte[])encoded : null;
@@ -89,11 +103,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
file = map.get(name);
}
if (file == NullVirtualFile.INSTANCE) {
return createIfNotFound ? createAndFindChildWithEventFire(name) : null;
}
if (file != null) return (NewVirtualFile)file;
if (file != null) return file;
if (ensureCanonicalName) {
final NewVirtualFileSystem delegate = getFileSystem();
@@ -131,6 +141,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
return name.equalsIgnoreCase(name2);
}
@NotNull
public VirtualFileSystemEntry createChild(String name, int id) {
final VirtualFileSystemEntry child;
final NewVirtualFileSystem fs = getFileSystem();
@@ -149,7 +160,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
}
@Nullable
private NewVirtualFile createAndFindChildWithEventFire(final String name) {
private NewVirtualFile createAndFindChildWithEventFire(@NotNull String name) {
final NewVirtualFileSystem delegate = getFileSystem();
VirtualFile fake = new FakeVirtualFile(this, name);
if (delegate.exists(fake)) {
@@ -164,12 +175,12 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
}
@Nullable
public NewVirtualFile refreshAndFindChild(final String name) {
public NewVirtualFile refreshAndFindChild(@NotNull String name) {
return findChild(name, true, true);
}
@Nullable
public synchronized NewVirtualFile findChildIfCached(final String name) {
public synchronized NewVirtualFile findChildIfCached(@NotNull String name) {
final VirtualFile[] a = asArray();
if (a != null) {
Object encoded = encodeName(name);
@@ -191,6 +202,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
}
@Override
@NotNull
public Iterable<VirtualFile> iterInDbChildren() {
return ContainerUtil.iterate(getInDbChildren(), new Condition<VirtualFile>() {
public boolean value(VirtualFile file) {
@@ -228,17 +240,19 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
return (VirtualFile[])myChildren;
}
final int[] childrenIds = ourPersistence.listIds(this);
Pair<String[],int[]> pair = PersistentFS.listAll(this);
final int[] childrenIds = pair.second;
VirtualFile[] children;
if (childrenIds.length == 0) {
children = EMPTY_ARRAY;
}
else {
children = new VirtualFile[childrenIds.length];
String[] names = pair.first;
final Map<String, VirtualFile> map = asMap();
for (int i = 0; i < children.length; i++) {
final int childId = childrenIds[i];
final String name = ourPersistence.getName(childId);
final String name = names[i];
VirtualFile child = map != null ? map.get(name) : null;
children[i] = child != null && child != NullVirtualFile.INSTANCE ? child : createChild(name, childId);
@@ -293,21 +307,21 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
}
@Nullable
private synchronized VirtualFile[] asArray() {
private VirtualFile[] asArray() {
if (myChildren instanceof VirtualFile[]) return (VirtualFile[])myChildren;
return null;
}
@Nullable
@SuppressWarnings({"unchecked"})
private synchronized Map<String, VirtualFile> asMap() {
private Map<String, VirtualFile> asMap() {
if (myChildren instanceof Map) return (Map<String, VirtualFile>)myChildren;
return null;
}
@NotNull
@SuppressWarnings({"unchecked"})
private synchronized Map<String, VirtualFile> ensureAsMap() {
private Map<String, VirtualFile> ensureAsMap() {
Map<String, VirtualFile> map;
if (myChildren == null) {
map = createMap();
@@ -320,7 +334,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
return map;
}
public synchronized void addChild(VirtualFile file) {
public synchronized void addChild(@NotNull VirtualFile file) {
final VirtualFile[] a = asArray();
if (a != null) {
myChildren = ArrayUtil.append(a, file);
@@ -331,7 +345,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
}
}
public synchronized void removeChild(VirtualFile file) {
public synchronized void removeChild(@NotNull VirtualFile file) {
final VirtualFile[] a = asArray();
if (a != null) {
myChildren = ArrayUtil.remove(a, file);
@@ -346,7 +360,8 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
return myChildren instanceof VirtualFile[];
}
public synchronized List<String> getSuspicousNames() {
@NotNull
public synchronized List<String> getSuspiciousNames() {
final Map<String, VirtualFile> map = asMap();
if (map == null) return Collections.emptyList();
@@ -379,6 +394,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
return Collections.emptyList();
}
@NotNull
private Map<String, VirtualFile> createMap() {
return getFileSystem().isCaseSensitive()
? new THashMap<String, VirtualFile>()
@@ -386,14 +402,15 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
}
@TestOnly
public synchronized void cleanupCachedChildren(Set<VirtualFile> survivors) {
public synchronized void cleanupCachedChildren(@NotNull Set<VirtualFile> survivors) {
if (survivors.contains(this)) {
for (VirtualFile file : getCachedChildren()) {
if (file instanceof VirtualDirectoryImpl) {
((VirtualDirectoryImpl)file).cleanupCachedChildren(survivors);
}
}
} else {
}
else {
myChildren = null;
}
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.Forceable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.util.io.ByteSequence;
import com.intellij.openapi.util.io.FileUtil;
@@ -88,7 +89,7 @@ public class FSRecords implements Forceable {
private static final String CHILDREN_ATT = "FsRecords.DIRECTORY_CHILDREN";
private static final Object lock = new Object();
private volatile static int ourLocalModificationCount = 0;
private static volatile int ourLocalModificationCount = 0;
private static final int FREE_RECORD_FLAG = 0x100;
private static final int ALL_VALID_FLAGS = PersistentFS.ALL_VALID_FLAGS | FREE_RECORD_FLAG;
@@ -205,8 +206,8 @@ public class FSRecords implements Forceable {
boolean deleted = true;
deleted &= FileUtil.delete(getCorruptionMarkerFile());
deleted &= deleteWithSubordinates(namesFile);
deleted &= Storage.deleteFiles(attributesFile.getCanonicalPath());
deleted &= Storage.deleteFiles(contentsFile.getCanonicalPath());
deleted &= AbstractStorage.deleteFiles(attributesFile.getCanonicalPath());
deleted &= AbstractStorage.deleteFiles(contentsFile.getCanonicalPath());
deleted &= deleteWithSubordinates(recordsFile);
if (!deleted) {
@@ -259,7 +260,12 @@ public class FSRecords implements Forceable {
}
private static File basePath() {
return new File(PathManager.getSystemPath() + "/caches/");
return new File(getCachesDir());
}
private static String getCachesDir() {
String dir = System.getProperty("caches_dir");
return dir == null ? PathManager.getSystemPath() + "/caches/" : dir;
}
private static boolean deleteWithSubordinates(File file) {
@@ -280,7 +286,7 @@ public class FSRecords implements Forceable {
return ok;
}
private static void markDirty() throws IOException {
private static void markDirty() {
if (!myDirty) {
myDirty = true;
myRecords.putInt(HEADER_CONNECTION_STATUS_OFFSET, CONNECTED_MAGIC);
@@ -302,13 +308,8 @@ public class FSRecords implements Forceable {
public static void force() {
synchronized (lock) {
try {
if (myRecords != null) {
markClean();
}
}
catch (IOException e) {
LOG.info(e);
if (myRecords != null) {
markClean();
}
if (myNames != null) {
myNames.force();
@@ -329,12 +330,7 @@ public class FSRecords implements Forceable {
final boolean attribsFlushed = myAttributes.flushSome();
final boolean contentsFlushed = myContents.flushSome();
if (attribsFlushed && contentsFlushed) {
try {
markClean();
}
catch (IOException e) {
// Ignore
}
markClean();
myRecords.force();
}
}
@@ -345,7 +341,7 @@ public class FSRecords implements Forceable {
}
private static int getVersion() throws IOException {
private static int getVersion() {
final int recordsVersion = myRecords.getInt(HEADER_VERSION_OFFSET);
if (myAttributes.getVersion() != recordsVersion || myContents.getVersion() != recordsVersion) return -1;
@@ -356,7 +352,7 @@ public class FSRecords implements Forceable {
return myRecords.getLong(HEADER_TIMESTAMP_OFFSET);
}
private static void setCurrentVersion() throws IOException {
private static void setCurrentVersion() {
myRecords.putInt(HEADER_VERSION_OFFSET, VERSION);
myRecords.putLong(HEADER_TIMESTAMP_OFFSET, System.currentTimeMillis());
myAttributes.setVersion(VERSION);
@@ -364,7 +360,7 @@ public class FSRecords implements Forceable {
myRecords.putInt(HEADER_CONNECTION_STATUS_OFFSET, SAFELY_CLOSED_MAGIC);
}
public static void cleanRecord(final int id) throws IOException {
public static void cleanRecord(final int id) {
myRecords.put(id * RECORD_SIZE, ZEROES, 0, RECORD_SIZE);
}
@@ -376,7 +372,7 @@ public class FSRecords implements Forceable {
return myRecords;
}
public void dispose() throws IOException {
public static void dispose() throws IOException {
synchronized (lock) {
refCount--;
if (refCount == 0) {
@@ -413,7 +409,7 @@ public class FSRecords implements Forceable {
}
}
private static void markClean() throws IOException {
private static void markClean() {
if (myDirty) {
myDirty = false;
myRecords.putInt(HEADER_CONNECTION_STATUS_OFFSET, myCorrupted ? CORRUPTED_MAGIC : SAFELY_CLOSED_MAGIC);
@@ -449,11 +445,11 @@ public class FSRecords implements Forceable {
public FSRecords() {
}
public void connect() {
public static void connect() {
DbConnection.connect();
}
public long getCreationTimestamp() {
public static long getCreationTimestamp() {
synchronized (lock) {
return DbConnection.getTimestamp();
}
@@ -500,7 +496,7 @@ public class FSRecords implements Forceable {
}
}
public void deleteRecordRecursively(int id) {
public static void deleteRecordRecursively(int id) {
synchronized (lock) {
try {
DbConnection.markDirty();
@@ -513,7 +509,7 @@ public class FSRecords implements Forceable {
}
}
private void doDeleteRecursively(final int id) {
private static void doDeleteRecursively(final int id) {
for (int subrecord : list(id)) {
doDeleteRecursively(subrecord);
}
@@ -521,7 +517,7 @@ public class FSRecords implements Forceable {
deleteRecord(id);
}
private void deleteRecord(final int id) {
private static void deleteRecord(final int id) {
synchronized (lock) {
try {
DbConnection.markDirty();
@@ -536,7 +532,7 @@ public class FSRecords implements Forceable {
}
}
private void deleteContentAndAttributes(int id) throws IOException {
private static void deleteContentAndAttributes(int id) throws IOException {
int content_page = getContentRecordId(id);
if (content_page != 0) {
getContentStorage().releaseRecord(content_page);
@@ -555,12 +551,12 @@ public class FSRecords implements Forceable {
}
}
private void addToFreeRecordsList(int id) throws IOException {
private static void addToFreeRecordsList(int id) {
DbConnection.addFreeRecord(id);
setFlags(id, FREE_RECORD_FLAG, false);
}
public int[] listRoots() throws IOException {
public static int[] listRoots() throws IOException {
synchronized (lock) {
DbConnection.markDirty();
final DataInputStream input = readAttribute(1, CHILDREN_ATT);
@@ -591,7 +587,7 @@ public class FSRecords implements Forceable {
return DbConnection.isDirty();
}
public int findRootRecord(String rootUrl) throws IOException {
public static int findRootRecord(String rootUrl) throws IOException {
synchronized (lock) {
DbConnection.markDirty();
final int root = getNames().enumerate(rootUrl);
@@ -641,7 +637,7 @@ public class FSRecords implements Forceable {
}
}
public void deleteRootRecord(int id) throws IOException {
public static void deleteRootRecord(int id) throws IOException {
synchronized (lock) {
DbConnection.markDirty();
final DataInputStream input = readAttribute(1, CHILDREN_ATT);
@@ -683,7 +679,7 @@ public class FSRecords implements Forceable {
}
}
public int[] list(int id) {
public static int[] list(int id) {
synchronized (lock) {
try {
final DataInputStream input = readAttribute(id, CHILDREN_ATT);
@@ -702,8 +698,30 @@ public class FSRecords implements Forceable {
}
}
}
public static Pair<String[],int[]> listAll(int parentId) {
synchronized (lock) {
try {
final DataInputStream input = readAttribute(parentId, CHILDREN_ATT);
if (input == null) return Pair.create(ArrayUtil.EMPTY_STRING_ARRAY, ArrayUtil.EMPTY_INT_ARRAY);
public boolean wereChildrenAccessed(int id) {
final int count = input.readInt();
final int[] ids = ArrayUtil.newIntArray(count);
final String[] names = ArrayUtil.newStringArray(count);
for (int i = 0; i < count; i++) {
int id = input.readInt();
ids[i] = id;
names[i] = getName(id);
}
input.close();
return Pair.create(names, ids);
}
catch (Throwable e) {
throw DbConnection.handleError(e);
}
}
}
public static boolean wereChildrenAccessed(int id) {
try {
synchronized (lock) {
return findAttributePage(id, CHILDREN_ATT, false) != 0;
@@ -714,7 +732,7 @@ public class FSRecords implements Forceable {
}
}
public void updateList(int id, int[] children) {
public static void updateList(int id, int[] children) {
synchronized (lock) {
try {
DbConnection.markDirty();
@@ -736,7 +754,7 @@ public class FSRecords implements Forceable {
}
}
private static void incModCount(int id) throws IOException {
private static void incModCount(int id) {
ourLocalModificationCount++;
final int count = getModCount() + 1;
getRecords().putInt(HEADER_GLOBAL_MODCOUNT_OFFSET, count);
@@ -775,7 +793,7 @@ public class FSRecords implements Forceable {
}
}
public void setParent(int id, int parent) {
public static void setParent(int id, int parent) {
if (id == parent) {
LOG.error("Cyclic parent/child relations");
return;
@@ -805,7 +823,7 @@ public class FSRecords implements Forceable {
}
}
public void setName(int id, String name) {
public static void setName(int id, String name) {
synchronized (lock) {
try {
DbConnection.markDirty();
@@ -824,7 +842,7 @@ public class FSRecords implements Forceable {
}
}
public void setFlags(int id, int flags, final boolean markAsChange) {
public static void setFlags(int id, int flags, final boolean markAsChange) {
synchronized (lock) {
try {
if (markAsChange) {
@@ -845,7 +863,7 @@ public class FSRecords implements Forceable {
}
}
public void setLength(int id, long len) {
public static void setLength(int id, long len) {
synchronized (lock) {
try {
DbConnection.markDirty();
@@ -864,7 +882,7 @@ public class FSRecords implements Forceable {
}
}
public void setTimestamp(int id, long value) {
public static void setTimestamp(int id, long value) {
synchronized (lock) {
try {
DbConnection.markDirty();
@@ -883,23 +901,23 @@ public class FSRecords implements Forceable {
}
}
private static void setModCount(int id, int value) throws IOException {
private static void setModCount(int id, int value) {
putRecordInt(id, MODCOUNT_OFFSET, value);
}
private static int getContentRecordId(int fileId) throws IOException {
private static int getContentRecordId(int fileId) {
return getRecordInt(fileId, CONTENT_OFFSET);
}
private static void setContentRecordId(int id, int value) throws IOException {
private static void setContentRecordId(int id, int value) {
putRecordInt(id, CONTENT_OFFSET, value);
}
private static int getAttributeRecordId(int id) throws IOException {
private static int getAttributeRecordId(int id) {
return getRecordInt(id, ATTREF_OFFSET);
}
private static void setAttributeRecordId(int id, int value) throws IOException {
private static void setAttributeRecordId(int id, int value) {
putRecordInt(id, ATTREF_OFFSET, value);
}
@@ -916,7 +934,7 @@ public class FSRecords implements Forceable {
}
@Nullable
public DataInputStream readContent(int fileId) {
public static DataInputStream readContent(int fileId) {
try {
int page;
synchronized (lock) {
@@ -931,7 +949,7 @@ public class FSRecords implements Forceable {
}
@Nullable
public DataInputStream readContentById(int contentId) {
public static DataInputStream readContentById(int contentId) {
try {
return getContentStorage().readStream(contentId);
}
@@ -941,7 +959,7 @@ public class FSRecords implements Forceable {
}
@Nullable
public DataInputStream readAttribute(int fileId, String attId) {
public static DataInputStream readAttribute(int fileId, String attId) {
try {
synchronized (attId) {
int page;
@@ -957,7 +975,7 @@ public class FSRecords implements Forceable {
}
}
private int findContentPage(int fileId, boolean toWrite) throws IOException {
private static int findContentPage(int fileId, boolean toWrite) throws IOException {
checkFileIsValid(fileId);
int recordId = getContentRecordId(fileId);
@@ -971,7 +989,7 @@ public class FSRecords implements Forceable {
return recordId;
}
private int findAttributePage(int fileId, String attrId, boolean toWrite) throws IOException {
private static int findAttributePage(int fileId, String attrId, boolean toWrite) throws IOException {
checkFileIsValid(fileId);
Storage storage = getAttributesStorage();
@@ -1012,13 +1030,13 @@ public class FSRecords implements Forceable {
return 0;
}
private void checkFileIsValid(int fileId) {
private static void checkFileIsValid(int fileId) {
assert fileId > 0 : "assert fileId > 0 failed";
// TODO: This assertion is a bit timey, will remove when bug is caught.
assert (getFlags(fileId) & FREE_RECORD_FLAG) == 0 : "Trying to find an attribute of deleted page";
}
public int acquireFileContent(int fileId) {
public static int acquireFileContent(int fileId) {
try {
synchronized (lock) {
int record = getContentRecordId(fileId);
@@ -1031,7 +1049,7 @@ public class FSRecords implements Forceable {
}
}
public void releaseContent(int contentId) {
public static void releaseContent(int contentId) {
try {
getContentStorage().releaseRecord(contentId);
}
@@ -1040,7 +1058,7 @@ public class FSRecords implements Forceable {
}
}
public int getContentId(int fileId) {
public static int getContentId(int fileId) {
try {
synchronized (lock) {
return getContentRecordId(fileId);
@@ -1052,15 +1070,15 @@ public class FSRecords implements Forceable {
}
@NotNull
public DataOutputStream writeContent(int fileId, boolean readOnly) {
public static DataOutputStream writeContent(int fileId, boolean readOnly) {
return new ContentOutputStream(fileId, readOnly);
}
public void writeContent(int fileId, ByteSequence bytes, boolean readOnly) throws IOException {
public static void writeContent(int fileId, ByteSequence bytes, boolean readOnly) throws IOException {
new ContentOutputStream(fileId, readOnly).writeBytes(bytes, fileId);
}
public int storeUnlinkedContent(byte[] bytes) {
public static int storeUnlinkedContent(byte[] bytes) {
try {
int recordId = getContentStorage().acquireNewRecord();
AbstractStorage.StorageDataOutput output = getContentStorage().writeStream(recordId);
@@ -1074,12 +1092,11 @@ public class FSRecords implements Forceable {
}
@NotNull
public DataOutputStream writeAttribute(final int fileId, final String attId, boolean fixedSize) {
public static DataOutputStream writeAttribute(final int fileId, final String attId, boolean fixedSize) {
return new AttributeOutputStream(fileId, attId, fixedSize);
}
private class ContentOutputStream extends BaseOutputStream {
private static class ContentOutputStream extends BaseOutputStream {
private ContentOutputStream(final int fileId, boolean readOnly) {
super(fileId, readOnly);
}
@@ -1095,7 +1112,7 @@ public class FSRecords implements Forceable {
}
}
private class AttributeOutputStream extends BaseOutputStream {
private static class AttributeOutputStream extends BaseOutputStream {
private final String myAttributeId;
private AttributeOutputStream(final int fileId, final String attributeId, boolean fixedSize) {
@@ -1163,7 +1180,7 @@ public class FSRecords implements Forceable {
protected abstract AbstractStorage getStorage();
}
public void dispose() {
public static void dispose() {
synchronized (lock) {
try {
DbConnection.force();
@@ -1180,7 +1197,7 @@ public class FSRecords implements Forceable {
}
public static void checkSanity() {
long startTime = System.currentTimeMillis();
//long startTime = System.currentTimeMillis();
synchronized (lock) {
final int fileLength = (int)getRecords().length();
assert fileLength % RECORD_SIZE == 0;
@@ -1201,7 +1218,7 @@ public class FSRecords implements Forceable {
}
}
long endTime = System.currentTimeMillis();
//long endTime = System.currentTimeMillis();
//System.out.println("Sanity check took " + (endTime-startTime) + " ms");
}
@@ -1227,26 +1244,15 @@ public class FSRecords implements Forceable {
}
private static void checkContentsStorageSanity(int id) {
try {
int recordId = getContentRecordId(id);
assert recordId >= 0;
if (recordId > 0) {
getContentStorage().checkSanity(recordId);
}
}
catch (IOException e) {
throw DbConnection.handleError(e);
int recordId = getContentRecordId(id);
assert recordId >= 0;
if (recordId > 0) {
getContentStorage().checkSanity(recordId);
}
}
private static void checkAttributesStorageSanity(int id, IntArrayList usedAttributeRecordIds, IntArrayList validAttributeIds) {
int attributeRecordId;
try {
attributeRecordId = getAttributeRecordId(id);
}
catch (IOException ex) {
throw DbConnection.handleError(ex);
}
int attributeRecordId = getAttributeRecordId(id);
assert attributeRecordId >= 0;
if (attributeRecordId > 0) {
@@ -1267,7 +1273,7 @@ public class FSRecords implements Forceable {
final DataInputStream dataInputStream = getAttributesStorage().readStream(attributeRecordId);
try {
final int streamSize = dataInputStream.available();
assert (streamSize % 8) == 0;
assert streamSize % 8 == 0;
for (int i = 0; i < streamSize / 8; i++) {
int attId = dataInputStream.readInt();
int attDataRecordId = dataInputStream.readInt();
@@ -23,6 +23,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.ApplicationEx;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.util.io.ByteSequence;
@@ -59,7 +60,6 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
public static final long FILE_LENGTH_TO_CACHE_THRESHOLD = 20 * 1024 * 1024; // 20 megabytes
private final FSRecords myRecords;
private final MessageBus myEventsBus;
private final Map<String, NewVirtualFile> myRoots = new HashMap<String, NewVirtualFile>();
@@ -73,7 +73,6 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
public PersistentFS(MessageBus bus) {
myEventsBus = bus;
myRecords = new FSRecords();
/*
PropertiesComponent properties = PropertiesComponent.getInstance();
@@ -100,7 +99,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
private void performShutdown() {
if (!myShutdownPerformed.getAndSet(Boolean.TRUE)) {
LOG.info("VFS dispose started");
myRecords.dispose();
FSRecords.dispose();
LOG.info("VFS dispose completed");
}
}
@@ -112,7 +111,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
public void initComponent() {
myRecords.connect();
FSRecords.connect();
}
public boolean areChildrenLoaded(final VirtualFile dir) {
@@ -120,7 +119,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
public long getCreationTimestamp() {
return myRecords.getCreationTimestamp();
return FSRecords.getCreationTimestamp();
}
private static NewVirtualFileSystem getDelegate(VirtualFile file) {
@@ -128,25 +127,25 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
public boolean wereChildrenAccessed(final VirtualFile dir) {
return myRecords.wereChildrenAccessed(getFileId(dir));
return FSRecords.wereChildrenAccessed(getFileId(dir));
}
public String[] list(final VirtualFile file) {
int id = getFileId(file);
int[] childrenIds = FSRecords.list(id);
String[] names = listPersisted(childrenIds);
if (areChildrenLoaded(id)) {
return listPersisted(file);
}
else {
return persistAllChildren(file);
return names;
}
Pair<String[], int[]> pair = persistAllChildren(file, id, Pair.create(names, childrenIds));
return pair.first;
}
public String[] listPersisted(final VirtualFile file) {
return listPersisted(getFileId(file));
return listPersisted(FSRecords.list(getFileId(file)));
}
private String[] listPersisted(final int id) {
final int[] childrenIds = myRecords.list(id);
private static String[] listPersisted(int[] childrenIds) {
String[] names = ArrayUtil.newStringArray(childrenIds.length);
for (int i = 0; i < childrenIds.length; i++) {
names[i] = FSRecords.getName(childrenIds[i]);
@@ -154,14 +153,15 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
return names;
}
private String[] persistAllChildren(final VirtualFile file) {
int id = getFileId(file);
String[] currentNames = listPersisted(file);
int[] currentIds = myRecords.list(id);
private static Pair<String[],int[]> persistAllChildren(final VirtualFile file, int id, Pair<String[],int[]> current) {
String[] currentNames = current.first;
int[] currentIds = current.second;
final NewVirtualFileSystem delegate = getDelegate(file);
String[] delegateNames = VfsUtil.filterNames(delegate.list(file));
if (delegateNames.length == 0 && currentNames.length > 0) return currentNames;
if (delegateNames.length == 0 && currentNames.length > 0) {
return current;
}
final String[] names;
if (currentNames.length == 0) {
@@ -189,21 +189,34 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
}
myRecords.updateList(id, childrenIds);
FSRecords.updateList(id, childrenIds);
int flags = FSRecords.getFlags(id);
myRecords.setFlags(id, flags | CHILDREN_CACHED_FLAG, true);
FSRecords.setFlags(id, flags | CHILDREN_CACHED_FLAG, true);
return names;
return Pair.create(names, childrenIds);
}
public int[] listIds(VirtualFile parent) {
public static int[] listIds(VirtualFile parent) {
final int parentId = getFileId(parent);
int[] ids = FSRecords.list(parentId);
if (!areChildrenLoaded(parentId)) {
list(parent);
String[] names = listPersisted(ids);
Pair<String[], int[]> pair = persistAllChildren(parent, parentId, Pair.create(names, ids));
return pair.second;
}
return myRecords.list(parentId);
return ids;
}
public static Pair<String[],int[]> listAll(VirtualFile parent) {
final int parentId = getFileId(parent);
Pair<String[], int[]> pair = FSRecords.listAll(parentId);
if (!areChildrenLoaded(parentId)) {
return persistAllChildren(parent, parentId, pair);
}
return pair;
}
@@ -214,33 +227,33 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
@Nullable
public DataInputStream readAttribute(final VirtualFile file, final FileAttribute att) {
return myRecords.readAttribute(getFileId(file), att.getId());
return FSRecords.readAttribute(getFileId(file), att.getId());
}
public DataOutputStream writeAttribute(final VirtualFile file, final FileAttribute att) {
return myRecords.writeAttribute(getFileId(file), att.getId(), att.isFixedSize());
return FSRecords.writeAttribute(getFileId(file), att.getId(), att.isFixedSize());
}
@Nullable
private DataInputStream readContent(VirtualFile file) {
return myRecords.readContent(getFileId(file));
private static DataInputStream readContent(VirtualFile file) {
return FSRecords.readContent(getFileId(file));
}
@Nullable
private DataInputStream readContentById(int contentId) {
return myRecords.readContentById(contentId);
private static DataInputStream readContentById(int contentId) {
return FSRecords.readContentById(contentId);
}
private DataOutputStream writeContent(VirtualFile file, boolean readOnly) {
return myRecords.writeContent(getFileId(file), readOnly);
private static DataOutputStream writeContent(VirtualFile file, boolean readOnly) {
return FSRecords.writeContent(getFileId(file), readOnly);
}
private void writeContent(VirtualFile file, ByteSequence content, boolean readOnly) throws IOException {
myRecords.writeContent(getFileId(file), content, readOnly);
private static void writeContent(VirtualFile file, ByteSequence content, boolean readOnly) throws IOException {
FSRecords.writeContent(getFileId(file), content, readOnly);
}
public int storeUnlinkedContent(byte[] bytes) {
return myRecords.storeUnlinkedContent(bytes);
return FSRecords.storeUnlinkedContent(bytes);
}
public int getModificationCount(final VirtualFile file) {
@@ -257,7 +270,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
return FSRecords.getModCount();
}
private void copyRecordFromDelegateFS(final int id, final int parentId, final VirtualFile file, NewVirtualFileSystem delegate) {
private static void copyRecordFromDelegateFS(final int id, final int parentId, final VirtualFile file, NewVirtualFileSystem delegate) {
if (id == parentId) {
LOG.error("Cyclic parent-child relations for file: " + file);
return;
@@ -271,13 +284,13 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
if (areChildrenLoaded(id)) return;
}
myRecords.setParent(id, parentId);
myRecords.setName(id, name);
FSRecords.setParent(id, parentId);
FSRecords.setName(id, name);
myRecords.setTimestamp(id, delegate.getTimeStamp(file));
myRecords.setFlags(id, (delegate.isDirectory(file) ? IS_DIRECTORY_FLAG : 0) | (delegate.isWritable(file) ? 0 : IS_READ_ONLY), true);
FSRecords.setTimestamp(id, delegate.getTimeStamp(file));
FSRecords.setFlags(id, (delegate.isDirectory(file) ? IS_DIRECTORY_FLAG : 0) | (delegate.isWritable(file) ? 0 : IS_READ_ONLY), true);
myRecords.setLength(id, -1L);
FSRecords.setLength(id, -1L);
// TODO!!!: More attributes?
}
@@ -313,7 +326,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
public void setTimeStamp(final VirtualFile file, final long modstamp) throws IOException {
final int id = getFileId(file);
myRecords.setTimestamp(id, modstamp);
FSRecords.setTimestamp(id, modstamp);
getDelegate(file).setTimeStamp(file, modstamp);
}
@@ -340,7 +353,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
final NewVirtualFileSystem delegate = getDelegate(parent);
final int parentId = getFileId(parent);
final int[] children = myRecords.list(parentId);
final int[] children = FSRecords.list(parentId);
for (final int childId : children) {
if (namesEqual(delegate, childName, FSRecords.getName(childId))) return childId;
}
@@ -349,7 +362,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
if (delegate.exists(fake)) {
int child = FSRecords.createRecord();
copyRecordFromDelegateFS(child, parentId, fake, delegate);
myRecords.updateList(parentId, ArrayUtil.append(children, child));
FSRecords.updateList(parentId, ArrayUtil.append(children, child));
return child;
}
@@ -362,7 +375,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
long len = FSRecords.getLength(id);
if (len == -1) {
len = (int)getDelegate(file).getLength(file);
myRecords.setLength(id, len);
FSRecords.setLength(id, len);
}
return len;
@@ -436,12 +449,12 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
final byte[] content = delegate.contentsToByteArray(file);
ApplicationEx application = (ApplicationEx)ApplicationManager.getApplication();
if ((!delegate.isReadOnly() || (!application.isInternal() && !application.isUnitTestMode())) &&
if ((!delegate.isReadOnly() || !application.isInternal() && !application.isUnitTestMode()) &&
!noCaching && content.length <= FILE_LENGTH_TO_CACHE_THRESHOLD) {
synchronized (INPUT_LOCK) {
writeContent(file, new ByteSequence(content), delegate.isReadOnly());
myRecords.setLength(getFileId(file), content.length);
FSRecords.setLength(getFileId(file), content.length);
setFlag(file, MUST_RELOAD_CONTENT, false);
}
}
@@ -490,7 +503,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
synchronized (INPUT_LOCK) {
if (getBytesRead() == len) {
writeContent(file, new ByteSequence(cache.getInternalBuffer(), 0, cache.size()), readOnly);
myRecords.setLength(getFileId(file), len);
FSRecords.setLength(getFileId(file), len);
setFlag(file, MUST_RELOAD_CONTENT, false);
}
else {
@@ -553,15 +566,15 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
public int acquireContent(VirtualFile file) {
return myRecords.acquireFileContent(getFileId(file));
return FSRecords.acquireFileContent(getFileId(file));
}
public void releaseContent(int contentId) {
myRecords.releaseContent(contentId);
FSRecords.releaseContent(contentId);
}
public int getCurrentContentId(VirtualFile file) {
return myRecords.getContentId(getFileId(file));
return FSRecords.getContentId(getFileId(file));
}
public void moveFile(final Object requestor, final VirtualFile file, final VirtualFile newParent) throws IOException {
@@ -622,11 +635,12 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
events = validateEvents(events);
myEventsBus.syncPublisher(VirtualFileManager.VFS_CHANGES).before(events);
BulkFileListener publisher = myEventsBus.syncPublisher(VirtualFileManager.VFS_CHANGES);
publisher.before(events);
for (VFileEvent event : events) {
applyEvent(event);
}
myEventsBus.syncPublisher(VirtualFileManager.VFS_CHANGES).after(events);
publisher.after(events);
}
public static final Object LOCK = new Object();
@@ -641,7 +655,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
if (root == null) {
try {
final int rootId = myRecords.findRootRecord(rootUrl);
final int rootId = FSRecords.findRootRecord(rootUrl);
if (basePath.length() > 0) {
root = new VirtualDirectoryImpl(basePath, null, fs, rootId);
}
@@ -819,7 +833,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
return "PersistentFS";
}
private void executeCreateChild(final VirtualFile parent, final String name) {
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)) {
@@ -833,10 +847,10 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
}
private void appendIdToParentList(final int parentId, final int childId) {
int[] childrenlist = myRecords.list(parentId);
private static void appendIdToParentList(final int parentId, final int childId) {
int[] childrenlist = FSRecords.list(parentId);
childrenlist = ArrayUtil.append(childrenlist, childId);
myRecords.updateList(parentId, childrenlist);
FSRecords.updateList(parentId, childrenlist);
}
private void executeDelete(final VirtualFile file) {
@@ -851,7 +865,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
final VirtualFile parent = file.getParent();
final int parentId = parent != null ? getFileId(parent) : 0;
myRecords.deleteRecordRecursively(id);
FSRecords.deleteRecordRecursively(id);
if (parentId != 0) {
removeIdFromParentList(parentId, id);
@@ -864,7 +878,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
synchronized (LOCK) {
myRoots.remove(file.getUrl());
try {
myRecords.deleteRootRecord(id);
FSRecords.deleteRootRecord(id);
}
catch (IOException e) {
throw new RuntimeException(e);
@@ -884,32 +898,32 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
}
private void removeIdFromParentList(final int parentId, final int id) {
int[] childList = myRecords.list(parentId);
private static void removeIdFromParentList(final int parentId, final int id) {
int[] childList = FSRecords.list(parentId);
childList = ArrayUtil.remove(childList, ArrayUtil.indexOf(childList, id));
myRecords.updateList(parentId, childList);
FSRecords.updateList(parentId, childList);
}
private void executeRename(final VirtualFile file, final String newName) {
private static void executeRename(final VirtualFile file, final String newName) {
((VirtualFileSystemEntry)file).setName(newName);
final int id = getFileId(file);
myRecords.setName(id, newName);
FSRecords.setName(id, newName);
}
private void executeSetWritable(final VirtualFile file, final boolean writableFlag) {
private static void executeSetWritable(final VirtualFile file, final boolean writableFlag) {
setFlag(file, IS_READ_ONLY, !writableFlag);
}
private void setFlag(VirtualFile file, int mask, boolean value) {
private static void setFlag(VirtualFile file, int mask, boolean value) {
setFlag(getFileId(file), mask, value);
}
private void setFlag(final int id, final int mask, final boolean value) {
private static void setFlag(final int id, final int mask, final boolean value) {
int oldFlags = FSRecords.getFlags(id);
int flags = value ? oldFlags | mask : oldFlags & ~mask;
if (oldFlags != flags) {
myRecords.setFlags(id, flags, true);
FSRecords.setFlags(id, flags, true);
}
}
@@ -917,24 +931,24 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
return (FSRecords.getFlags(getFileId(file)) & mask) != 0;
}
private void executeTouch(final VirtualFile file, boolean reloadContentFromDelegate, long newModificationStamp) {
private static void executeTouch(final VirtualFile file, boolean reloadContentFromDelegate, long newModificationStamp) {
if (reloadContentFromDelegate) {
setFlag(file, MUST_RELOAD_CONTENT, true);
}
final NewVirtualFileSystem delegate = getDelegate(file);
myRecords.setLength(getFileId(file), delegate.getLength(file));
myRecords.setTimestamp(getFileId(file), delegate.getTimeStamp(file));
FSRecords.setLength(getFileId(file), delegate.getLength(file));
FSRecords.setTimestamp(getFileId(file), delegate.getTimeStamp(file));
((NewVirtualFile)file).setModificationStamp(newModificationStamp);
}
@SuppressWarnings({"UnusedDeclaration"})
private void executeCopy(final VirtualFile from, final VirtualFile newParent, final String copyName) {
private static void executeCopy(final VirtualFile from, final VirtualFile newParent, final String copyName) {
executeCreateChild(newParent, copyName);
}
private void executeMove(final VirtualFile what, final VirtualFile newParent) {
private static void executeMove(final VirtualFile what, final VirtualFile newParent) {
final int whatId = getFileId(what);
final int newParentId = getFileId(newParent);
final int oldParentId = getFileId(what.getParent());
@@ -943,7 +957,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
appendIdToParentList(newParentId, whatId);
((VirtualFileSystemEntry)what).setParent(newParent);
myRecords.setParent(whatId, newParentId);
FSRecords.setParent(whatId, newParentId);
}
public String getName(final int id) {
@@ -953,7 +967,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
public void cleanPersistedContents() {
try {
final int[] roots = myRecords.listRoots();
final int[] roots = FSRecords.listRoots();
for (int root : roots) {
cleanPersistedContentsRecursively(root);
}
@@ -965,7 +979,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
private void cleanPersistedContentsRecursively(int id) {
if (isDirectory(id)) {
for (int child : myRecords.list(id)) {
for (int child : FSRecords.list(id)) {
cleanPersistedContentsRecursively(child);
}
}
@@ -110,7 +110,7 @@ public class RefreshWorker {
}
}
final List<String> names = dir.getSuspicousNames();
final List<String> names = dir.getSuspiciousNames();
for (String name : names) {
if (name.length() == 0) continue;