db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From krist...@apache.org
Subject svn commit: r759176 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/io/ engine/org/apache/derby/impl/io/vfmem/ testing/org/apache/derbyTesting/unitTests/junit/
Date Fri, 27 Mar 2009 15:26:41 GMT
Author: kristwaa
Date: Fri Mar 27 15:26:39 2009
New Revision: 759176

URL: http://svn.apache.org/viewvc?rev=759176&view=rev
Log:
DERBY-4125: The in-memory storage back end doesn't work on Windows.
Changed the in-memory storage factory to rely much more on java.io.File to
handle paths and names.
The data store now stores all files and directories with normalized paths.
Also fixed a bug in DataStore.deleteEntry for deletion of directories.
Added two more tests; testListChildren and testCreateRoot.

Patch file: derby-4125-1a-improved_path_handling.diff


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStore.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStoreEntry.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/unitTests/junit/VirtualFileTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java?rev=759176&r1=759175&r2=759176&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java Fri
Mar 27 15:26:39 2009
@@ -58,7 +58,7 @@
             DataStore store = (DataStore)DATABASES.remove(dbName);
             if (store != null) {
                 // Delete everything.
-                store.deleteAll("/");
+                store.purge();
                 return true;
             }
             return false;
@@ -104,11 +104,8 @@
             throws IOException {
         // Handle cases where a database name is specified.
         if (databaseName != null) {
-            // TODO: Is using java.io.File the right thing to do?
-            //       Should we just set the canonical name equal to the
-            //       specified database name instead?
             if (home != null &&
-                    !databaseName.startsWith(String.valueOf(getSeparator()))) {
+                    !new File(databaseName).isAbsolute()) {
                 canonicalName = new File(home, databaseName).getCanonicalPath();
             } else {
                 canonicalName = new File(databaseName).getCanonicalPath();
@@ -307,7 +304,7 @@
     private String normalizePath(String dir, String file) {
         if (dir == null || dir.equals("")) {
             dir = dataDirectory.getPath();
-        } else if (dir.charAt(0) != getSeparator()) {
+        } else if (!new File(dir).isAbsolute()) {
             dir = new File(dataDirectory.getPath(), dir).getPath();
         }
         // We now have an absolute path for the directory.
@@ -324,7 +321,7 @@
     private String normalizePath(String path) {
         if (path == null || path.equals("")) {
             return dataDirectory.getPath();
-        } else if (path.charAt(0) == getSeparator()) {
+        } else if (new File(path).isAbsolute()) {
             return path;
         } else {
             return new File(dataDirectory.getPath(), path).getPath();

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStore.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStore.java?rev=759176&r1=759175&r2=759176&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStore.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStore.java Fri Mar
27 15:26:39 2009
@@ -21,6 +21,8 @@
 
 package org.apache.derby.impl.io.vfmem;
 
+import java.io.File;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
@@ -31,6 +33,8 @@
 /**
  * A virtual data store, keeping track of all the virtual files existing and
  * offering a set of high-level operations on virtual files.
+ * <p>
+ * A newly created data store doesn't contain a single existing directory.
  */
 public final class DataStore {
 
@@ -64,9 +68,6 @@
      */
     public DataStore(String databaseName) {
         this.databaseName = databaseName;
-        // Create the absolute root.
-        createEntry(String.valueOf(SEP), true);
-
     }
 
     /**
@@ -91,23 +92,24 @@
      *      created, {@code null} otherwise
      */
     public DataStoreEntry createEntry(String iPath, boolean isDir) {
+        // Normalize the path.
+        final String nPath = new File(iPath).getPath();
         synchronized (LOCK) {
-            if (files.containsKey(iPath)) {
+            if (files.containsKey(nPath)) {
                 return null;
             }
             // Make sure the the parent directories exists.
-            String parent = PathUtil.getParent(iPath);
-            while (parent != null) {
-                DataStoreEntry entry = (DataStoreEntry)files.get(parent);
+            String[] parents = getParentList(nPath);
+            for (int i=parents.length -1; i >= 0; i--) {
+                DataStoreEntry entry = (DataStoreEntry)files.get(parents[i]);
                 if (entry == null) {
                     return null;
                 } else if (!entry.isDirectory()) {
                     return null;
                 }
-                parent = PathUtil.getParent(parent);
             }
-            DataStoreEntry newEntry = new DataStoreEntry(iPath, isDir);
-            files.put(iPath, newEntry);
+            DataStoreEntry newEntry = new DataStoreEntry(nPath, isDir);
+            files.put(nPath, newEntry);
             return newEntry;
         }
     }
@@ -119,25 +121,19 @@
      *      or were created, {@code false} otherwise
      */
     public boolean createAllParents(String path) {
-        if (path.charAt(path.length() -1) == SEP) {
-            path = path.substring(0, path.length() -1);
-        }
-        // If there is no path separator, only one entry will be created.
-        if (path.indexOf(SEP) == -1) {
-            return true;
-        }
+        final String nPath = new File(path).getPath();
+        // Iterate through the list and create the missing parents.
+        String[] parents = getParentList(nPath);
         synchronized (LOCK) {
-            int index = path.indexOf(SEP, 1); // The root always exists
-
-            while (index > 0) {
-                String subPath = path.substring(0, index);
+            for (int i=parents.length -1; i >= 0; i--) {
+                String subPath = parents[i];
                 DataStoreEntry entry = (DataStoreEntry)files.get(subPath);
                 if (entry == null) {
                     createEntry(subPath, true);
                 } else if (!entry.isDirectory()) {
+                    // Fail if one of the parents is a regular file.
                     return false;
                 }
-                index = path.indexOf(SEP, index +1);
             }
         }
         return true;
@@ -153,21 +149,20 @@
      * @return {@code true} if the entry was deleted, {@code false} otherwise.
      */
     public boolean deleteEntry(String iPath) {
+        final String nPath = new File(iPath).getPath();
         DataStoreEntry entry;
         synchronized (LOCK) {
-            entry = (DataStoreEntry)files.remove(iPath);
+            entry = (DataStoreEntry)files.remove(nPath);
             if (entry != null) {
                 if (entry.isDirectory()) {
-                    String[] children = listChildren(iPath);
-                    if (children == null || children.length == 0){
-                        entry.release();
+                    String[] children = listChildren(nPath);
+                    if (children.length > 0) {
                         // Re-add the entry.
-                        files.put(iPath, entry);
+                        files.put(nPath, entry);
                         return false;
                     }
-                } else {
-                    entry.release();
                 }
+                entry.release();
             }
         }
         return (entry != null);
@@ -182,7 +177,8 @@
      */
     public DataStoreEntry getEntry(String iPath) {
         synchronized (LOCK) {
-            return (DataStoreEntry)files.get(iPath);
+            // Use java.io.File to normalize the path.
+            return (DataStoreEntry)files.get(new File(iPath).getPath());
         }
     }
 
@@ -194,14 +190,15 @@
      *      {@code false} if the root doesn't exist.
      */
     public boolean deleteAll(String iPath) {
+        final String nPath = new File(iPath).getPath();
         synchronized (LOCK) {
-            DataStoreEntry entry = (DataStoreEntry)files.remove(iPath);
+            DataStoreEntry entry = (DataStoreEntry)files.remove(nPath);
             if (entry == null) {
                 // Delete root doesn't exist.
                 return false;
             } else if (entry.isDirectory()) {
                 // Delete root is a directory.
-                return _deleteAll(iPath);
+                return _deleteAll(nPath);
             } else {
                 // Delete root is a file.
                 entry.release();
@@ -222,9 +219,10 @@
             throw new IllegalArgumentException(
                     "The empty string is not a valid path");
         }
+        String nPath = new File(iPath).getPath();
         // Make sure the search path ends with the separator.
-        if (iPath.charAt(iPath.length() -1) != SEP) {
-            iPath += SEP;
+        if (nPath.charAt(nPath.length() -1) != SEP) {
+            nPath += SEP;
         }
         ArrayList children = new ArrayList();
         synchronized (LOCK) {
@@ -232,8 +230,8 @@
             String candidate;
             while (paths.hasNext()) {
                 candidate = (String)paths.next();
-                if (candidate.startsWith(iPath)) {
-                    children.add(candidate.substring(iPath.length()));
+                if (candidate.startsWith(nPath)) {
+                    children.add(candidate.substring(nPath.length()));
                 }
             }
         }
@@ -249,30 +247,51 @@
      *      file already existed or the existing file doesn't exist.
      */
     public boolean move(StorageFile currentFile, StorageFile newFile) {
+        final String currentPath = new File(currentFile.getPath()).getPath();
+        final String newPath = new File(newFile.getPath()).getPath();
         synchronized (LOCK) {
-            if (files.containsKey(newFile.getPath())) {
+            if (files.containsKey(newPath)) {
                 return false;
             }
             DataStoreEntry current = (DataStoreEntry)
-                    files.remove(currentFile.getPath());
+                    files.remove(currentPath);
             if (current == null) {
                 return false;
             }
-            files.put(newFile.getPath(), current);
+            files.put(newPath, current);
             return true;
         }
     }
 
     /**
+     * Purges the database and releases all files associated with it.
+     */
+    public void purge() {
+        synchronized (LOCK) {
+            Iterator fileIter = files.values().iterator();
+            while (fileIter.hasNext()) {
+                ((DataStoreEntry)fileIter.next()).release();
+            }
+            // Clear all the mappings.
+            files.clear();
+        }
+    }
+
+    /**
      * Deletes every child of the root path specified.
      * <p>
      * Note that the root itself must be removed outside of this method.
      *
-     * @param prefixPath the root path to start deleting from
+     * @param prefixPath the normalized root path to start deleting from
      * @return {@code true} if all children of the root path were deleted,
      *      {@code false} otherwise.
      */
+    //@GuardedBy("LOCK")
     private boolean _deleteAll(String prefixPath) {
+        // Make sure the search path ends with the separator.
+        if (prefixPath.charAt(prefixPath.length() -1) != SEP) {
+            prefixPath += SEP;
+        }
         ArrayList toDelete = new ArrayList();
         Iterator paths = files.keySet().iterator();
         // Find all the entries to delete.
@@ -289,9 +308,7 @@
         while (keys.hasNext()) {
             DataStoreEntry entry = (DataStoreEntry)
                     files.remove((String)keys.next());
-            if (!entry.isDirectory()) {
-                entry.release();
-            }
+            entry.release();
         }
         return true;
     }
@@ -306,4 +323,23 @@
             return ++tmpFileCounter;
         }
     }
+
+    /**
+     * Returns the list of parents for the specified path.
+     * <p>
+     * The lowest level parent is listed first in the list, so all absolute
+     * paths will have the root listed as the last element.
+     *
+     * @param path the normalized path to create a parent list for
+     * @return A list of parents.
+     */
+    private String[] getParentList(String path) {
+        ArrayList parents = new ArrayList();
+        String parent = path;
+        // Build the list of parents.
+        while ((parent = new File(parent).getParent()) != null) {
+            parents.add(parent);
+        }
+        return (String[])parents.toArray(new String[parents.size()]);
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStoreEntry.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStoreEntry.java?rev=759176&r1=759175&r2=759176&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStoreEntry.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/io/vfmem/DataStoreEntry.java Fri
Mar 27 15:26:39 2009
@@ -147,7 +147,9 @@
      */
     void release() {
         released = true;
-        src.release();
+        if (src != null) {
+            src.release();
+        }
     }
 
     /**

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/unitTests/junit/VirtualFileTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/unitTests/junit/VirtualFileTest.java?rev=759176&r1=759175&r2=759176&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/unitTests/junit/VirtualFileTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/unitTests/junit/VirtualFileTest.java
Fri Mar 27 15:26:39 2009
@@ -272,6 +272,70 @@
         assertTrue(vFile.isDirectory());
     }
 
+    /**
+     * Tests that {@code listChildren} doesn't include too many entries.
+     */
+    public void testListChilderen() {
+        DataStore store = getStore();
+        VirtualFile dir1 = new VirtualFile(PathUtilTest.abs("mydir"), store);
+        VirtualFile dir2 = new VirtualFile(
+                PathUtilTest.abs("mydirectory"), store);
+        VirtualFile file1 = new VirtualFile(
+                PathUtilTest.joinAbs("mydir", "file1.txt"), store);
+        VirtualFile file2 = new VirtualFile(
+                PathUtilTest.joinAbs("mydirectory", "file2.txt"), store);
+        assertTrue(dir1.mkdirs());
+        assertTrue(dir1.exists());
+        assertTrue(dir1.isDirectory());
+        assertTrue(dir2.mkdirs());
+        assertTrue(dir2.exists());
+        assertTrue(dir2.isDirectory());
+        assertTrue(file1.createNewFile());
+        assertTrue(file1.exists());
+        assertFalse(file1.isDirectory());
+        assertTrue(file2.createNewFile());
+        assertTrue(file2.exists());
+        assertFalse(file2.isDirectory());
+        // We should only get one child; file1.txt
+        String[] children = dir1.list();
+        assertEquals(1, children.length);
+        assertEquals(file1.getName(), children[0]);
+        // Test that the same path ending with the separator results in the
+        // same list being returned.
+        VirtualFile dir1abs = new VirtualFile(
+                PathUtilTest.joinAbs("mydir", ""), store);
+        assertFalse(dir1.getName().equals(dir1abs.getName()));
+        String[] childrenAbs = dir1abs.list();
+        assertEquals(1, childrenAbs.length);
+        assertEquals(children[0], childrenAbs[0]);
+        // The deleteAll below shouldn't delete "mydirectory" and "file2.txt"..
+        assertFalse(dir1.delete());
+        assertTrue(dir1.deleteAll());
+        assertTrue(dir2.exists());
+        assertTrue(file2.exists());
+    }
+
+    /**
+     * Makes sure that the root can be created.
+     */
+    public void testCreateRoot() {
+        DataStore store = new DataStore("testCreateRootStore");
+        String path = PathUtilTest.joinAbs("these", "are", "directories");
+        assertTrue(store.createAllParents(path));
+        assertNotNull(store.createEntry(path, true));
+        VirtualFile vf = new VirtualFile(path, store);
+        assertTrue(vf.exists());
+        assertTrue(vf.isDirectory());
+
+        // Also test one Windows specific root.
+        path = PathUtilTest.join("c:", "Documents and Settings", "directories");
+        assertTrue(store.createAllParents(path));
+        assertNotNull(store.createEntry(path, true));
+        vf = new VirtualFile(path, store);
+        assertTrue(vf.exists());
+        assertTrue(vf.isDirectory());
+    }
+
     public static Test suite() {
         return new TestSuite(VirtualFileTest.class);
     }
@@ -280,6 +344,9 @@
     private static int dbStoreIndex = 0;
     /** Utility method returning a fresh data store. */
     private static synchronized DataStore getStore() {
-        return new DataStore("testVFMemDB-" + dbStoreIndex++);
+        DataStore store = new DataStore("testVFMemDB-" + dbStoreIndex++);
+        // We need the root to exist.
+        assertNotNull(store.createEntry(java.io.File.separator, true));
+        return store;
     }
 }



Mime
View raw message