summaryrefslogtreecommitdiffstats
path: root/sched
diff options
context:
space:
mode:
authorBenoit Lamarche <benoitlamarche@google.com>2015-02-02 16:14:34 +0100
committerBenoit Lamarche <benoitlamarche@google.com>2015-02-06 12:34:22 +0100
commit9455008864906968cbe9d061162319dcdc1cefa1 (patch)
tree8cb11627ac16e70e70875ea4190ade5e4532b2d5 /sched
parent08cb1e6efe6099be1435544c62ec30ea51716064 (diff)
downloadtoolchain_jack-9455008864906968cbe9d061162319dcdc1cefa1.tar.gz
toolchain_jack-9455008864906968cbe9d061162319dcdc1cefa1.tar.bz2
toolchain_jack-9455008864906968cbe9d061162319dcdc1cefa1.zip
Retry adding CachedDirectFS
Change-Id: I389b367f5a425ea58733b8f8dc8533464d3974d7
Diffstat (limited to 'sched')
-rw-r--r--sched/src/com/android/sched/util/codec/DirectDirInputOutputVFSCodec.java4
-rw-r--r--sched/src/com/android/sched/util/codec/DirectFSCodec.java4
-rw-r--r--sched/src/com/android/sched/vfs/CachedDirectFS.java407
-rw-r--r--sched/src/com/android/sched/vfs/InMemoryVDir.java18
-rw-r--r--sched/src/com/android/sched/vfs/ReadWriteZipFS.java4
-rw-r--r--sched/tests/com/android/sched/vfs/VFSTest.java49
6 files changed, 476 insertions, 10 deletions
diff --git a/sched/src/com/android/sched/util/codec/DirectDirInputOutputVFSCodec.java b/sched/src/com/android/sched/util/codec/DirectDirInputOutputVFSCodec.java
index 4630b85b..0e79e2fd 100644
--- a/sched/src/com/android/sched/util/codec/DirectDirInputOutputVFSCodec.java
+++ b/sched/src/com/android/sched/util/codec/DirectDirInputOutputVFSCodec.java
@@ -19,7 +19,7 @@ package com.android.sched.util.codec;
import com.android.sched.util.file.Directory;
import com.android.sched.util.file.FileOrDirectory.Existence;
-import com.android.sched.vfs.DirectFS;
+import com.android.sched.vfs.CachedDirectFS;
import com.android.sched.vfs.GenericInputOutputVFS;
import com.android.sched.vfs.InputOutputVFS;
@@ -49,7 +49,7 @@ public class DirectDirInputOutputVFSCodec extends InputOutputVFSCodec
public InputOutputVFS checkString(@Nonnull CodecContext context,
@Nonnull final String string) throws ParsingException {
try {
- return new GenericInputOutputVFS(new DirectFS(new Directory(string,
+ return new GenericInputOutputVFS(new CachedDirectFS(new Directory(string,
context.getRunnableHooks(), existence, permissions, change), permissions));
} catch (IOException e) {
throw new ParsingException(e);
diff --git a/sched/src/com/android/sched/util/codec/DirectFSCodec.java b/sched/src/com/android/sched/util/codec/DirectFSCodec.java
index beedf8b1..78a69a73 100644
--- a/sched/src/com/android/sched/util/codec/DirectFSCodec.java
+++ b/sched/src/com/android/sched/util/codec/DirectFSCodec.java
@@ -22,7 +22,7 @@ import com.android.sched.util.file.Directory;
import com.android.sched.util.file.FileOrDirectory.ChangePermission;
import com.android.sched.util.file.FileOrDirectory.Existence;
import com.android.sched.util.file.FileOrDirectory.Permission;
-import com.android.sched.vfs.DirectFS;
+import com.android.sched.vfs.CachedDirectFS;
import com.android.sched.vfs.VFS;
import java.io.IOException;
@@ -90,7 +90,7 @@ public class DirectFSCodec extends FileOrDirCodec implements StringCodec<VFS> {
public VFS checkString(@Nonnull CodecContext context,
@Nonnull final String string) throws ParsingException {
try {
- return new DirectFS(new Directory(string,
+ return new CachedDirectFS(new Directory(string,
context.getRunnableHooks(), existence, permissions, change), permissions);
} catch (IOException e) {
throw new ParsingException(e);
diff --git a/sched/src/com/android/sched/vfs/CachedDirectFS.java b/sched/src/com/android/sched/vfs/CachedDirectFS.java
new file mode 100644
index 00000000..1c47aa6e
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/CachedDirectFS.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sched.vfs;
+
+import com.android.sched.util.ConcurrentIOException;
+import com.android.sched.util.file.AbstractStreamFile;
+import com.android.sched.util.file.CannotCreateFileException;
+import com.android.sched.util.file.CannotDeleteFileException;
+import com.android.sched.util.file.Directory;
+import com.android.sched.util.file.FileAlreadyExistsException;
+import com.android.sched.util.file.FileOrDirectory;
+import com.android.sched.util.file.FileOrDirectory.Permission;
+import com.android.sched.util.file.NoSuchFileException;
+import com.android.sched.util.file.NotDirectoryException;
+import com.android.sched.util.file.NotFileException;
+import com.android.sched.util.file.WrongPermissionException;
+import com.android.sched.util.location.DirectoryLocation;
+import com.android.sched.util.location.FileLocation;
+import com.android.sched.util.location.Location;
+import com.android.sched.vfs.CachedDirectFS.CachedParentVDir;
+import com.android.sched.vfs.CachedDirectFS.CachedParentVFile;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link VFS} implementation backed by a real file system, but where directories are cached in
+ * memory.
+ */
+public class CachedDirectFS extends BaseVFS<CachedParentVDir, CachedParentVFile> implements VFS {
+
+ static class CachedParentVDir extends InMemoryVDir {
+
+ @CheckForNull
+ private CachedParentVDir parent;
+
+ CachedParentVDir(@Nonnull BaseVFS<? extends CachedParentVDir, ? extends ParentVFile> vfs,
+ @Nonnull String name) {
+ super(vfs, name);
+ }
+
+ CachedParentVDir(@Nonnull BaseVFS<? extends CachedParentVDir, ? extends ParentVFile> vfs,
+ @Nonnull CachedParentVDir parent, @Nonnull String name) {
+ super(vfs, name);
+ this.parent = parent;
+ }
+
+ @Override
+ @Nonnull
+ public VPath getPath() {
+ if (parent != null) {
+ return parent.getPath().clone().appendPath(new VPath(name, '/'));
+ } else {
+ return VPath.ROOT;
+ }
+ }
+
+ @Override
+ @Nonnull
+ public BaseVFile getVFile(@Nonnull String name) throws NoSuchFileException,
+ NotFileException {
+ return vfs.getVFile(this, name);
+ }
+
+ @Override
+ @Nonnull
+ public BaseVDir getVDir(@Nonnull String name) throws NotDirectoryException,
+ NoSuchFileException {
+ return vfs.getVDir(this, name);
+ }
+
+ @Override
+ @Nonnull
+ public BaseVFile createVFile(@Nonnull String name) throws CannotCreateFileException {
+ return vfs.createVFile(this, name);
+ }
+
+ @Override
+ @Nonnull
+ public BaseVDir createVDir(@Nonnull String name) throws CannotCreateFileException {
+ return vfs.createVDir(this, name);
+ }
+
+ @Override
+ @Nonnull
+ public Collection<? extends BaseVElement> list() {
+ return vfs.list(this);
+ }
+ }
+
+ static class CachedParentVFile extends ParentVFile {
+
+ CachedParentVFile(@Nonnull BaseVFS<? extends BaseVDir, ? extends BaseVFile> vfs,
+ @Nonnull VDir parent, @Nonnull String name) {
+ super(vfs, parent, name);
+ }
+
+ @Override
+ public void delete() throws CannotDeleteFileException {
+ vfs.delete(this);
+ }
+
+ public void deleteFromCache() {
+ ((InMemoryVDir) parent).internalDelete(name);
+ }
+ }
+
+ @Nonnull
+ private final Directory dir;
+ @Nonnull
+ private final CachedParentVDir root;
+ @Nonnull
+ private final Set<Capabilities> capabilities;
+
+ public CachedDirectFS(@Nonnull Directory dir, int permissions) {
+ this.dir = dir;
+ this.root = new CachedParentVDir(this, "");
+
+ Set<Capabilities> capabilities = EnumSet.noneOf(Capabilities.class);
+ if ((permissions & Permission.READ) != 0) {
+ capabilities.add(Capabilities.READ);
+ capabilities.add(Capabilities.PARALLEL_READ);
+ }
+ if ((permissions & Permission.WRITE) != 0) {
+ capabilities.add(Capabilities.WRITE);
+ capabilities.add(Capabilities.PARALLEL_WRITE);
+ }
+ capabilities.add(Capabilities.UNIQUE_ELEMENT);
+ this.capabilities = Collections.unmodifiableSet(capabilities);
+
+ fillVDirFromRealDirectory(dir.getFile(), root);
+ }
+
+ private void fillVDirFromRealDirectory(@Nonnull File dir, @Nonnull VDir vDir) {
+ for (File element : dir.listFiles()) {
+ try {
+ if (element.isDirectory()) {
+ VDir newVDir = vDir.createVDir(element.getName());
+ fillVDirFromRealDirectory(element, newVDir);
+ } else {
+ vDir.createVFile(element.getName());
+ }
+ } catch (CannotCreateFileException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ @Override
+ @Nonnull
+ public String getDescription() {
+ return "directory on disk with cache";
+ }
+
+ @Nonnull
+ @Override
+ public Set<Capabilities> getCapabilities() {
+ return capabilities;
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return root.getLocation();
+ }
+
+ @Override
+ public synchronized void close() {
+ closed = true;
+ }
+
+ @Override
+ @Nonnull
+ public String getPath() {
+ return dir.getPath();
+ }
+
+ @Override
+ public CachedParentVDir getRootDir() {
+ return root;
+ }
+
+ @Override
+ @Nonnull
+ InputStream openRead(@Nonnull CachedParentVFile file) throws WrongPermissionException {
+ assert !isClosed();
+ assert capabilities.contains(Capabilities.READ);
+
+ File path = getNativeFile(file.getPath());
+ try {
+ return new FileInputStream(path);
+ } catch (FileNotFoundException e) {
+ FileOrDirectory.checkPermissions(path, file.getLocation(), Permission.READ);
+ throw new ConcurrentIOException(e);
+ }
+ }
+
+ @Nonnull
+ @Override
+ OutputStream openWrite(@Nonnull CachedParentVFile file) throws WrongPermissionException {
+ assert !isClosed();
+ assert capabilities.contains(Capabilities.WRITE);
+
+ File path = getNativeFile(file.getPath());
+ try {
+ return new FileOutputStream(path);
+ } catch (FileNotFoundException e) {
+ FileOrDirectory.checkPermissions(path, file.getLocation(), Permission.WRITE);
+ throw new ConcurrentIOException(e);
+ }
+ }
+
+ @Nonnull
+ @Override
+ Collection<? extends BaseVElement> list(@Nonnull CachedParentVDir dir) {
+ return dir.getAllFromCache();
+ }
+
+ @Override
+ boolean isEmpty(@Nonnull CachedParentVDir dir) {
+ assert !isClosed();
+ assert capabilities.contains(Capabilities.READ);
+
+ return getNativeFile(dir.getPath()).listFiles().length == 0;
+ }
+
+ @Override
+ @Nonnull
+ CachedParentVDir getVDir(@Nonnull CachedParentVDir parent, @Nonnull String name)
+ throws NotDirectoryException, NoSuchFileException {
+ BaseVElement element = parent.getFromCache(name);
+ if (element != null) {
+ if (element.isVDir()) {
+ return (CachedParentVDir) element;
+ } else {
+ throw new NotDirectoryException(getVDirLocation(parent, name));
+ }
+ } else {
+ throw new NoSuchFileException(getVDirLocation(parent, name));
+ }
+ }
+
+ @Override
+ @Nonnull
+ CachedParentVFile getVFile(@Nonnull CachedParentVDir parent, @Nonnull String name)
+ throws NotFileException, NoSuchFileException {
+ BaseVElement element = parent.getFromCache(name);
+ if (element != null) {
+ if (!element.isVDir()) {
+ return (CachedParentVFile) element;
+ } else {
+ throw new NotFileException(getVFileLocation(parent, name));
+ }
+ } else {
+ throw new NoSuchFileException(getVFileLocation(parent, name));
+ }
+ }
+
+ @Override
+ @Nonnull
+ void delete(@Nonnull CachedParentVFile file) throws CannotDeleteFileException {
+ assert !isClosed();
+
+ File path = getNativeFile(file.getPath());
+ if (!path.delete() || path.exists()) {
+ throw new CannotDeleteFileException(file.getLocation());
+ }
+
+ file.deleteFromCache();
+ }
+
+
+ @Override
+ @Nonnull
+ synchronized CachedParentVFile createVFile(@Nonnull CachedParentVDir parent, @Nonnull String name)
+ throws CannotCreateFileException {
+ assert !isClosed();
+
+ try {
+ return getVFile(parent, name);
+
+ } catch (NoSuchFileException e) {
+
+ File path = getNativeFile(parent.getPath(), name);
+ try {
+ AbstractStreamFile.create(path, new FileLocation(path));
+ } catch (FileAlreadyExistsException e2) {
+ // Nothing to do
+ }
+ CachedParentVFile vFile = new CachedParentVFile(this, parent, name);
+
+ parent.putInCache(name, vFile);
+ return vFile;
+
+ } catch (NotFileException e) {
+ throw new CannotCreateFileException(getVFileLocation(parent, name));
+ }
+ }
+
+ @Override
+ @Nonnull
+ synchronized CachedParentVDir createVDir(@Nonnull CachedParentVDir parent, @Nonnull String name)
+ throws CannotCreateFileException {
+ assert !isClosed();
+
+ try {
+ return getVDir(parent, name);
+
+ } catch (NoSuchFileException e) {
+
+ File path = getNativeFile(parent.getPath(), name);
+ try {
+ Directory.create(path, new DirectoryLocation(path));
+ } catch (FileAlreadyExistsException e2) {
+ // Nothing to do
+ }
+ CachedParentVDir vDir = new CachedParentVDir(this, parent, name);
+
+ parent.putInCache(name, vDir);
+ return vDir;
+
+ } catch (NotDirectoryException e) {
+ throw new CannotCreateFileException(getVDirLocation(parent, name));
+ }
+ }
+
+ @Override
+ public boolean needsSequentialWriting() {
+ return false;
+ }
+
+ @Override
+ synchronized boolean isClosed() {
+ return closed;
+ }
+
+ @Override
+ @Nonnull
+ FileLocation getVFileLocation(@Nonnull CachedParentVFile file) {
+ return new FileLocation(getNativeFile(file.getPath()));
+ }
+
+ @Override
+ @Nonnull
+ FileLocation getVFileLocation(@Nonnull CachedParentVDir parent, @Nonnull String name) {
+ return new FileLocation(getNativeFile(parent.getPath(), name));
+ }
+
+ @Override
+ @Nonnull
+ DirectoryLocation getVDirLocation(@Nonnull CachedParentVDir dir) {
+ return new DirectoryLocation(getNativeFile(dir.getPath()));
+ }
+
+ @Override
+ @Nonnull
+ DirectoryLocation getVDirLocation(@Nonnull CachedParentVDir parent, @Nonnull String name) {
+ return new DirectoryLocation(getNativeFile(parent.getPath(), name));
+ }
+
+ @Override
+ @Nonnull
+ FileLocation getVFileLocation(CachedParentVDir parent, VPath path) {
+ return new FileLocation(getNativeFile(parent.getPath().clone().appendPath(path)));
+ }
+
+ @Override
+ @Nonnull
+ DirectoryLocation getVDirLocation(CachedParentVDir parent, VPath path) {
+ return new DirectoryLocation(getNativeFile(parent.getPath().clone().appendPath(path)));
+ }
+
+ @Nonnull
+ private File getNativeFile(@Nonnull VPath path) {
+ return new File(dir.getFile(), path.getPathAsString(File.separatorChar));
+ }
+
+ @Nonnull
+ private File getNativeFile(@Nonnull VPath path, @Nonnull String name) {
+ return new File(new File(dir.getFile(), path.getPathAsString(File.separatorChar)), name);
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/InMemoryVDir.java b/sched/src/com/android/sched/vfs/InMemoryVDir.java
index 6d05a3f8..4ace1fcd 100644
--- a/sched/src/com/android/sched/vfs/InMemoryVDir.java
+++ b/sched/src/com/android/sched/vfs/InMemoryVDir.java
@@ -26,6 +26,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
@@ -113,7 +114,9 @@ abstract class InMemoryVDir extends BaseVDir {
@Override
@Nonnull
public synchronized Collection<? extends BaseVElement> list() {
- assert !vfs.isClosed();
+// assert !vfs.isClosed();
+ // STOPSHIP: There is a problem with this assertion, likely due to PrefixedFS that has a close()
+ // method that is not related to the the close() method of the underlying VFS.
return Collections.unmodifiableCollection(map.values());
}
@@ -126,5 +129,18 @@ abstract class InMemoryVDir extends BaseVDir {
synchronized void internalDelete(@Nonnull String name) {
map.remove(name);
}
+
+ @CheckForNull
+ synchronized BaseVElement getFromCache(@Nonnull String name) {
+ return map.get(name);
+ }
+
+ synchronized void putInCache(@Nonnull String name, @Nonnull BaseVElement vElement) {
+ map.put(name, vElement);
+ }
+
+ synchronized Collection<? extends BaseVElement> getAllFromCache() {
+ return map.values();
+ }
}
diff --git a/sched/src/com/android/sched/vfs/ReadWriteZipFS.java b/sched/src/com/android/sched/vfs/ReadWriteZipFS.java
index 6ce9d0a1..7664e4c8 100644
--- a/sched/src/com/android/sched/vfs/ReadWriteZipFS.java
+++ b/sched/src/com/android/sched/vfs/ReadWriteZipFS.java
@@ -62,8 +62,8 @@ public class ReadWriteZipFS extends BaseVFS<BaseVDir, BaseVFile> implements VFS
CannotCreateFileException {
int permissions = Permission.READ | Permission.WRITE;
dir = Files.createTempDir();
- DirectFS workVFS = new DirectFS(new Directory(dir.getPath(), null, Existence.MUST_EXIST,
- permissions, ChangePermission.NOCHANGE), permissions);
+ CachedDirectFS workVFS = new CachedDirectFS(new Directory(dir.getPath(), null,
+ Existence.MUST_EXIST, permissions, ChangePermission.NOCHANGE), permissions);
WriteZipFS finalVFS = new WriteZipFS(file);
this.vfs = new VFSToVFSWrapper(workVFS, finalVFS);
}
diff --git a/sched/tests/com/android/sched/vfs/VFSTest.java b/sched/tests/com/android/sched/vfs/VFSTest.java
index 80d8ec26..0769a409 100644
--- a/sched/tests/com/android/sched/vfs/VFSTest.java
+++ b/sched/tests/com/android/sched/vfs/VFSTest.java
@@ -145,6 +145,50 @@ public class VFSTest {
}
@Test
+ public void testCachedDirectFS()
+ throws NotDirectoryException,
+ CannotCreateFileException,
+ WrongPermissionException,
+ CannotSetPermissionException,
+ NoSuchFileException,
+ FileAlreadyExistsException,
+ IOException {
+ File file = null;
+ InputOutputVFS directVFS = null;
+ InputOutputVFS directVFS2 = null;
+ try {
+ file = File.createTempFile("vfs", "dir");
+ String path = file.getAbsolutePath();
+ Assert.assertTrue(file.delete());
+
+ directVFS = new GenericInputOutputVFS(new CachedDirectFS(new Directory(path, null,
+ Existence.NOT_EXIST, Permission.WRITE, ChangePermission.NOCHANGE),
+ Permission.READ | Permission.WRITE));
+
+ testOutputVFS(directVFS);
+ testDelete(directVFS);
+ testInputVFS(directVFS);
+ directVFS.close();
+
+ directVFS2 =
+ new GenericInputOutputVFS(new DirectFS(new Directory(path, null, Existence.MUST_EXIST,
+ Permission.WRITE, ChangePermission.NOCHANGE), Permission.READ | Permission.WRITE));
+ testInputVFS(directVFS2);
+
+ } finally {
+ if (directVFS != null) {
+ directVFS.close();
+ }
+ if (directVFS2 != null) {
+ directVFS2.close();
+ }
+ if (file != null) {
+ FileUtils.deleteDir(file);
+ }
+ }
+ }
+
+ @Test
public void testDeflateFS()
throws NotDirectoryException,
CannotCreateFileException,
@@ -560,8 +604,7 @@ public class VFSTest {
// let's delete "dirA/dirAA/dirAAB/fileAAB1"
InputOutputVDir dirA = ioVFS.getRootInputOutputVDir().getInputVDir(new VPath("dirA", '/'));
{
- InputOutputVFile fileAAB1 =
- (InputOutputVFile) dirA.getInputVFile(new VPath("dirAA/dirAAB/fileAAB1", '/'));
+ InputOutputVFile fileAAB1 = dirA.getInputVFile(new VPath("dirAA/dirAAB/fileAAB1", '/'));
fileAAB1.delete();
try {
ioVFS.getRootInputVDir().getInputVFile(new VPath("dirA/dirAA/dirAAB/fileAAB1", '/'));
@@ -575,7 +618,7 @@ public class VFSTest {
InputOutputVDir dirBB =
ioVFS.getRootInputOutputVDir().getInputVDir(new VPath("dirB/dirBB", '/'));
{
- InputOutputVFile fileBB1 = (InputOutputVFile) dirBB.getInputVFile(new VPath("fileBB1", '/'));
+ InputOutputVFile fileBB1 = dirBB.getInputVFile(new VPath("fileBB1", '/'));
fileBB1.delete();
try {
ioVFS.getRootInputVDir().getInputVFile(new VPath("dirB/dirBB/fileBB1", '/'));