This is an automated email from the ASF dual-hosted git repository.

gaul pushed a commit to branch local-blobstore/list-prefix
in repository https://gitbox.apache.org/repos/asf/jclouds.git

commit 29eec441e902162394a5dbceaf98c14d3b2bc87a
Author: Andrew Gaul <[email protected]>
AuthorDate: Fri Jan 25 11:42:13 2019 -0800

    JCLOUDS-1371: JCLOUDS-1488: list optimize prefix
    
    Previously getBlobKeysInsideContainer returned all keys and filtered
    in LocalBlobStore.  Now getBlobKeysInsideContainer filters via prefix
    which can dramatically decrease the number of keys returned,
    especially for the filesystem provider.  Further optimizations are
    possible for delimiter.
---
 .../internal/FilesystemStorageStrategyImpl.java    | 24 +++++++++++++++-------
 .../FilesystemStorageStrategyImplTest.java         |  8 ++++----
 .../jclouds/blobstore/LocalStorageStrategy.java    |  2 +-
 .../blobstore/TransientStorageStrategy.java        | 14 +++++++++----
 .../jclouds/blobstore/config/LocalBlobStore.java   |  4 ++--
 5 files changed, 34 insertions(+), 18 deletions(-)

diff --git 
a/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java
 
b/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java
index a9f0a9c..90876df 100644
--- 
a/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java
+++ 
b/apis/filesystem/src/main/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImpl.java
@@ -342,7 +342,7 @@ public class FilesystemStorageStrategyImpl implements 
LocalStorageStrategy {
     * @throws IOException
     */
    @Override
-   public Iterable<String> getBlobKeysInsideContainer(String container) throws 
IOException {
+   public Iterable<String> getBlobKeysInsideContainer(String container, String 
prefix) throws IOException {
       filesystemContainerNameValidator.validate(container);
       // check if container exists
       // TODO maybe an error is more appropriate
@@ -353,7 +353,7 @@ public class FilesystemStorageStrategyImpl implements 
LocalStorageStrategy {
 
       File containerFile = openFolder(container);
       final int containerPathLength = containerFile.getAbsolutePath().length() 
+ 1;
-      populateBlobKeysInContainer(containerFile, blobNames, new 
Function<String, String>() {
+      populateBlobKeysInContainer(containerFile, blobNames, prefix, new 
Function<String, String>() {
          @Override
          public String apply(String string) {
             return denormalize(string.substring(containerPathLength));
@@ -753,7 +753,7 @@ public class FilesystemStorageStrategyImpl implements 
LocalStorageStrategy {
    public long countBlobs(String container, ListContainerOptions options) {
       // TODO: honor options
       try {
-         return Iterables.size(getBlobKeysInsideContainer(container));
+         return Iterables.size(getBlobKeysInsideContainer(container, null));
       } catch (IOException ioe) {
          throw Throwables.propagate(ioe);
       }
@@ -964,17 +964,27 @@ public class FilesystemStorageStrategyImpl implements 
LocalStorageStrategy {
    }
 
    private static void populateBlobKeysInContainer(File directory, Set<String> 
blobNames,
-         Function<String, String> function) {
+         String prefix, Function<String, String> function) {
       File[] children = directory.listFiles();
       if (children == null) {
          return;
       }
       for (File child : children) {
+         String fullPath = function.apply(child.getAbsolutePath());
          if (child.isFile()) {
-            blobNames.add( function.apply(child.getAbsolutePath()) );
+            if (prefix != null && !fullPath.startsWith(prefix)) {
+               continue;
+            }
+            blobNames.add(fullPath);
          } else if (child.isDirectory()) {
-            blobNames.add(function.apply(child.getAbsolutePath()) + 
File.separator); // TODO: undo if failures
-            populateBlobKeysInContainer(child, blobNames, function);
+            // Consider a prefix /a/b/c but we have only descended to path /a.
+            // We need to match the path against the prefix to continue
+            // matching down to /a/b.
+            if (prefix != null && !fullPath.startsWith(prefix) && 
!prefix.startsWith(fullPath + "/")) {
+               continue;
+            }
+            blobNames.add(fullPath + File.separator); // TODO: undo if failures
+            populateBlobKeysInContainer(child, blobNames, prefix, function);
          }
       }
    }
diff --git 
a/apis/filesystem/src/test/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImplTest.java
 
b/apis/filesystem/src/test/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImplTest.java
index 7b4cb88..33157ce 100644
--- 
a/apis/filesystem/src/test/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImplTest.java
+++ 
b/apis/filesystem/src/test/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImplTest.java
@@ -427,7 +427,7 @@ public class FilesystemStorageStrategyImplTest {
       Blob blob = storageStrategy.newBlob(blobKey);
       storageStrategy.putBlob(CONTAINER_NAME, blob);
 
-      Iterable<String> keys = 
storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME);
+      Iterable<String> keys = 
storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME, null);
       Iterator<String> iter = keys.iterator();
       assertTrue(iter.hasNext());
       assertEquals(iter.next(), blobKey);
@@ -598,7 +598,7 @@ public class FilesystemStorageStrategyImplTest {
       Iterable<String> resultList;
 
       // no container
-      resultList = storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME);
+      resultList = storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME, 
null);
       assertNotNull(resultList, "Result is null");
       assertFalse(resultList.iterator().hasNext(), "Blobs detected");
 
@@ -609,10 +609,10 @@ public class FilesystemStorageStrategyImplTest {
                TestUtils.createRandomBlobKey("GetBlobKeys-", ".jpg"),
                TestUtils.createRandomBlobKey("563" + "/" + "g3sx2" + "/" + 
"removeBlob-", ".jpg"),
                TestUtils.createRandomBlobKey("563" + "/" + "g3sx2" + "/" + 
"removeBlob-", ".jpg") });
-      storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME);
+      storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME, null);
 
       List<String> retrievedBlobKeys = Lists.newArrayList();
-      resultList = storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME);
+      resultList = storageStrategy.getBlobKeysInsideContainer(CONTAINER_NAME, 
null);
       Iterator<String> containersIterator = resultList.iterator();
       while (containersIterator.hasNext()) {
          retrievedBlobKeys.add(containersIterator.next());
diff --git 
a/blobstore/src/main/java/org/jclouds/blobstore/LocalStorageStrategy.java 
b/blobstore/src/main/java/org/jclouds/blobstore/LocalStorageStrategy.java
index 1498ee1..1a0ebd8 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/LocalStorageStrategy.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/LocalStorageStrategy.java
@@ -98,7 +98,7 @@ public interface LocalStorageStrategy {
      * @return
      * @throws IOException
      */
-    Iterable<String> getBlobKeysInsideContainer(String container) throws 
IOException;
+    Iterable<String> getBlobKeysInsideContainer(String container, String 
prefix) throws IOException;
 
     /**
      * Load the blob with the given key belonging to the container with the 
given
diff --git 
a/blobstore/src/main/java/org/jclouds/blobstore/TransientStorageStrategy.java 
b/blobstore/src/main/java/org/jclouds/blobstore/TransientStorageStrategy.java
index bd662f3..3053aa4 100644
--- 
a/blobstore/src/main/java/org/jclouds/blobstore/TransientStorageStrategy.java
+++ 
b/blobstore/src/main/java/org/jclouds/blobstore/TransientStorageStrategy.java
@@ -25,6 +25,7 @@ import java.util.Date;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 
 import javax.inject.Inject;
 
@@ -59,7 +60,7 @@ import com.google.common.io.ByteStreams;
 import com.google.common.net.HttpHeaders;
 
 public class TransientStorageStrategy implements LocalStorageStrategy {
-   private final ConcurrentMap<String, ConcurrentMap<String, Blob>> 
containerToBlobs = new ConcurrentHashMap<String, ConcurrentMap<String, Blob>>();
+   private final ConcurrentMap<String, ConcurrentSkipListMap<String, Blob>> 
containerToBlobs = new ConcurrentHashMap<String, ConcurrentSkipListMap<String, 
Blob>>();
    private final ConcurrentMap<String, ConcurrentMap<String, BlobAccess>> 
containerToBlobAccess = new ConcurrentHashMap<String, ConcurrentMap<String, 
BlobAccess>>();
    private final ConcurrentMap<String, StorageMetadata> containerMetadata = 
new ConcurrentHashMap<String, StorageMetadata>();
    private final ConcurrentMap<String, ContainerAccess> containerAccessMap = 
new ConcurrentHashMap<String, ContainerAccess>();
@@ -90,7 +91,7 @@ public class TransientStorageStrategy implements 
LocalStorageStrategy {
    @Override
    public boolean createContainerInLocation(String containerName, Location 
location, CreateContainerOptions options) {
       ConcurrentMap<String, Blob> origValue = containerToBlobs.putIfAbsent(
-            containerName, new ConcurrentHashMap<String, Blob>());
+            containerName, new ConcurrentSkipListMap<String, Blob>());
       if (origValue != null) {
          return false;
       }
@@ -148,8 +149,13 @@ public class TransientStorageStrategy implements 
LocalStorageStrategy {
    }
 
    @Override
-   public Iterable<String> getBlobKeysInsideContainer(final String 
containerName) {
-      return containerToBlobs.get(containerName).keySet();
+   public Iterable<String> getBlobKeysInsideContainer(final String 
containerName, String prefix) {
+      ConcurrentSkipListMap<String, Blob> blobs = 
containerToBlobs.get(containerName);
+      if (prefix == null) {
+         return blobs.keySet();
+      }
+      String lastPrefix = prefix + (char) 65535;  // TODO: better sentinel?
+      return blobs.subMap(prefix, /*fromInclusive=*/ true, lastPrefix, 
/*toInclusive=*/ false).keySet();
    }
 
    @Override
diff --git 
a/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java 
b/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
index 3717ed4..b62ad18 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
@@ -238,7 +238,7 @@ public final class LocalBlobStore implements BlobStore {
       // Loading blobs from container
       Iterable<String> blobBelongingToContainer = null;
       try {
-         blobBelongingToContainer = 
storageStrategy.getBlobKeysInsideContainer(containerName);
+         blobBelongingToContainer = 
storageStrategy.getBlobKeysInsideContainer(containerName, options.getPrefix());
       } catch (IOException e) {
          logger.error(e, "An error occurred loading blobs contained into 
container %s", containerName);
          propagate(e);
@@ -414,7 +414,7 @@ public final class LocalBlobStore implements BlobStore {
       boolean returnVal = true;
       if (storageStrategy.containerExists(containerName)) {
          try {
-            if 
(Iterables.isEmpty(storageStrategy.getBlobKeysInsideContainer(containerName)))
+            if 
(Iterables.isEmpty(storageStrategy.getBlobKeysInsideContainer(containerName, 
null)))
                storageStrategy.deleteContainer(containerName);
             else
                returnVal = false;

Reply via email to