From a04484122a208f633749c3646b394b9515edca63 Mon Sep 17 00:00:00 2001 From: Roded Bahat Date: Tue, 14 Apr 2020 20:17:33 +0300 Subject: [PATCH] JCLOUDS-1543: change FetchBlobMetadata to retain original blob order --- .../strategy/internal/FetchBlobMetadata.java | 20 ++++- .../internal/FetchBlobMetadataTest.java | 82 +++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 blobstore/src/test/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadataTest.java diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java index 191ecbdb1e..535856dfd9 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java @@ -19,6 +19,9 @@ package org.jclouds.blobstore.strategy.internal; import static com.google.common.base.Preconditions.checkState; import static org.jclouds.concurrent.FutureIterables.transformParallel; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.concurrent.Callable; import javax.annotation.Resource; @@ -79,6 +82,15 @@ public class FetchBlobMetadata implements Function apply(PageSet in) { checkState(container != null, "container name should be initialized"); + if (in == null) { + return new PageSetImpl<>(Collections.emptyList(), null); + } + + Map orderedMap = new LinkedHashMap<>(in.size()); + for (StorageMetadata storageMetadata : in) { + orderedMap.put(storageMetadata.getName(), null); + } + Iterable returnv = Lists.newArrayList(transformParallel(in, new Function>() { @@ -88,7 +100,7 @@ public class FetchBlobMetadata implements Function() { - @Override public StorageMetadata call() throws Exception { + @Override public StorageMetadata call() { return blobstore.blobMetadata(container, from.getName()); } }); @@ -96,6 +108,10 @@ public class FetchBlobMetadata implements Function(returnv, in.getNextMarker()); + for (StorageMetadata storageMetadata : returnv) { + orderedMap.put(storageMetadata.getName(), storageMetadata); + } + + return new PageSetImpl<>(orderedMap.values(), in.getNextMarker()); } } diff --git a/blobstore/src/test/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadataTest.java b/blobstore/src/test/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadataTest.java new file mode 100644 index 0000000000..bd4cbb9015 --- /dev/null +++ b/blobstore/src/test/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadataTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.jclouds.blobstore.strategy.internal; + +import com.google.common.collect.Maps; +import com.google.common.collect.Ordering; +import com.google.inject.Injector; +import org.jclouds.ContextBuilder; +import org.jclouds.blobstore.BlobStore; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.blobstore.domain.PageSet; +import org.jclouds.blobstore.domain.StorageMetadata; +import org.jclouds.blobstore.options.ListContainerOptions; +import org.jclouds.util.Closeables2; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.Comparator; +import java.util.Map; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +@Test(testName = "FetchBlobMetadataTest", singleThreaded = true) +public class FetchBlobMetadataTest { + + private static final String CONTAINER_NAME = "container"; + + private BlobStore blobStore; + private FetchBlobMetadata fetchBlobMetadata; + + @BeforeClass + public void setupBlobStore() { + Injector injector = ContextBuilder.newBuilder("transient").buildInjector(); + blobStore = injector.getInstance(BlobStore.class); + fetchBlobMetadata = injector.getInstance(FetchBlobMetadata.class); + fetchBlobMetadata.setContainerName(CONTAINER_NAME); + } + + @AfterClass + public void closeBlobSore() { + if (blobStore != null) { + Closeables2.closeQuietly(blobStore.getContext()); + } + } + + @Test + public void testRetainsOriginalOrder() { + blobStore.createContainerInLocation(null, CONTAINER_NAME); + for (int blobIndex = 0; blobIndex < 20; blobIndex++) { + final Blob blob = blobStore.blobBuilder("prefix-" + blobIndex).payload("").build(); + blobStore.putBlob(CONTAINER_NAME, blob); + } + + final PageSet pageSet = + blobStore.list(CONTAINER_NAME, ListContainerOptions.Builder.withDetails()); + final PageSet resultPageSet = fetchBlobMetadata.apply(pageSet); + assertNotNull(resultPageSet); + + assertTrue(Ordering.from(new Comparator() { + @Override + public int compare(StorageMetadata o1, StorageMetadata o2) { + return o1.getName().compareTo(o2.getName()); + } + }).isOrdered(resultPageSet)); + } +}