Introduce TransientStorageStrategy

This allows code from the filesystem blobstore to be more similar to
the transient blobstore.  This commit also corrects a bug where
blobExists did not throw an exception when the container did not
exist.
This commit is contained in:
Andrew Gaul 2012-05-07 16:38:03 -07:00
parent 3a0c15b345
commit 442c51eb3c
3 changed files with 57 additions and 37 deletions

View File

@ -148,7 +148,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
public ListenableFuture<PageSet<? extends StorageMetadata>> list(final String container, ListContainerOptions options) { public ListenableFuture<PageSet<? extends StorageMetadata>> list(final String container, ListContainerOptions options) {
// Check if the container exists // Check if the container exists
if (!containerExistsSyncImpl(container)) if (!storageStrategy.containerExists(container))
return immediateFailedFuture(cnfe(container)); return immediateFailedFuture(cnfe(container));
// Loading blobs from container // Loading blobs from container
@ -242,7 +242,9 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
} }
private ContainerNotFoundException cnfe(final String name) { private ContainerNotFoundException cnfe(final String name) {
return new ContainerNotFoundException(name, String.format("container %s not in filesystem", name)); return new ContainerNotFoundException(name, String.format(
"container %s not in %s", name,
storageStrategy.getAllContainerNames()));
} }
public static MutableBlobMetadata copy(MutableBlobMetadata in) { public static MutableBlobMetadata copy(MutableBlobMetadata in) {
@ -304,7 +306,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<Boolean> containerExists(final String containerName) { public ListenableFuture<Boolean> containerExists(final String containerName) {
return immediateFuture(containerExistsSyncImpl(containerName)); return immediateFuture(storageStrategy.containerExists(containerName));
} }
/** /**
@ -503,6 +505,8 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<Boolean> blobExists(final String containerName, final String key) { public ListenableFuture<Boolean> blobExists(final String containerName, final String key) {
if (!storageStrategy.containerExists(containerName))
return immediateFailedFuture(cnfe(containerName));
return immediateFuture(storageStrategy.blobExists(containerName, key)); return immediateFuture(storageStrategy.blobExists(containerName, key));
} }
@ -513,7 +517,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
public ListenableFuture<Blob> getBlob(final String containerName, final String key, GetOptions options) { public ListenableFuture<Blob> getBlob(final String containerName, final String key, GetOptions options) {
logger.debug("Retrieving blob with key %s from container %s", key, containerName); logger.debug("Retrieving blob with key %s from container %s", key, containerName);
// If the container doesn't exist, an exception is thrown // If the container doesn't exist, an exception is thrown
if (!containerExistsSyncImpl(containerName)) { if (!storageStrategy.containerExists(containerName)) {
logger.debug("Container %s does not exist", containerName); logger.debug("Container %s does not exist", containerName);
return immediateFailedFuture(cnfe(containerName)); return immediateFailedFuture(cnfe(containerName));
} }
@ -601,17 +605,6 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
} }
} }
/**
* Each container is a directory, so in order to check if a container exists
* the corresponding directory must exists. Synchronous implementation
*
* @param containerName
* @return
*/
private boolean containerExistsSyncImpl(String containerName) {
return storageStrategy.containerExists(containerName);
}
/** /**
* Calculates the object MD5 and returns it as eTag * Calculates the object MD5 and returns it as eTag
* *
@ -633,7 +626,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
protected boolean deleteAndVerifyContainerGone(final String container) { protected boolean deleteAndVerifyContainerGone(final String container) {
storageStrategy.deleteContainer(container); storageStrategy.deleteContainer(container);
return containerExistsSyncImpl(container); return storageStrategy.containerExists(container);
} }
@Override @Override

View File

@ -565,8 +565,12 @@ public class FilesystemAsyncBlobStoreTest {
// when location doesn't exists // when location doesn't exists
blobKey = TestUtils.createRandomBlobKey(); blobKey = TestUtils.createRandomBlobKey();
result = blobStore.blobExists(CONTAINER_NAME, blobKey); try {
assertFalse(result, "Blob exists"); blobStore.blobExists(CONTAINER_NAME, blobKey);
fail();
} catch (ContainerNotFoundException cnfe) {
// expected
}
// when location exists // when location exists
blobStore.createContainerInLocation(null, CONTAINER_NAME); blobStore.createContainerInLocation(null, CONTAINER_NAME);

View File

@ -128,6 +128,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
protected final HttpGetOptionsListToGetOptions httpGetOptionsConverter; protected final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName; protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
protected final Factory blobFactory; protected final Factory blobFactory;
protected final TransientStorageStrategy storageStrategy;
@Inject @Inject
protected TransientAsyncBlobStore(BlobStoreContext context, protected TransientAsyncBlobStore(BlobStoreContext context,
@ -152,6 +153,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
this.ifDirectoryReturnName = ifDirectoryReturnName; this.ifDirectoryReturnName = ifDirectoryReturnName;
getContainerToLocation().put("stub", defaultLocation.get()); getContainerToLocation().put("stub", defaultLocation.get());
getContainerToBlobs().put("stub", new ConcurrentHashMap<String, Blob>()); getContainerToBlobs().put("stub", new ConcurrentHashMap<String, Blob>());
this.storageStrategy = new TransientStorageStrategy();
} }
/** /**
@ -246,8 +248,9 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
} }
private ContainerNotFoundException cnfe(final String name) { private ContainerNotFoundException cnfe(final String name) {
return new ContainerNotFoundException(name, String.format("container %s not in %s", name, getContainerToBlobs() return new ContainerNotFoundException(name, String.format(
.keySet())); "container %s not in %s", name,
storageStrategy.getAllContainerNames()));
} }
public static MutableBlobMetadata copy(MutableBlobMetadata in) { public static MutableBlobMetadata copy(MutableBlobMetadata in) {
@ -285,9 +288,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<Void> removeBlob(final String container, final String key) { public ListenableFuture<Void> removeBlob(final String container, final String key) {
if (getContainerToBlobs().containsKey(container)) { storageStrategy.removeBlob(container, key);
getContainerToBlobs().get(container).remove(key);
}
return immediateFuture(null); return immediateFuture(null);
} }
@ -305,17 +306,15 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<Void> deleteContainer(final String container) { public ListenableFuture<Void> deleteContainer(final String container) {
if (getContainerToBlobs().containsKey(container)) { deleteAndVerifyContainerGone(container);
getContainerToBlobs().remove(container);
}
return immediateFuture(null); return immediateFuture(null);
} }
public ListenableFuture<Boolean> deleteContainerIfEmpty(final String container) { public ListenableFuture<Boolean> deleteContainerIfEmpty(final String container) {
Boolean returnVal = true; Boolean returnVal = true;
if (getContainerToBlobs().containsKey(container)) { if (storageStrategy.containerExists(container)) {
if (getContainerToBlobs().get(container).size() == 0) if (getContainerToBlobs().get(container).size() == 0)
getContainerToBlobs().remove(container); storageStrategy.deleteContainer(container);
else else
returnVal = false; returnVal = false;
} }
@ -327,7 +326,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<Boolean> containerExists(final String containerName) { public ListenableFuture<Boolean> containerExists(final String containerName) {
return immediateFuture(getContainerToBlobs().containsKey(containerName)); return immediateFuture(storageStrategy.containerExists(containerName));
} }
/** /**
@ -335,7 +334,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list() { public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
Iterable<String> containers = getContainerToBlobs().keySet(); Iterable<String> containers = storageStrategy.getAllContainerNames();
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform( return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform(
containers, new Function<String, StorageMetadata>() { containers, new Function<String, StorageMetadata>() {
@ -358,7 +357,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<Boolean> createContainerInLocation(final Location location, final String name) { public ListenableFuture<Boolean> createContainerInLocation(final Location location, final String name) {
if (getContainerToBlobs().containsKey(name)) { if (storageStrategy.containerExists(name)) {
return immediateFuture(Boolean.FALSE); return immediateFuture(Boolean.FALSE);
} }
getContainerToBlobs().put(name, new ConcurrentHashMap<String, Blob>()); getContainerToBlobs().put(name, new ConcurrentHashMap<String, Blob>());
@ -542,10 +541,9 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<Boolean> blobExists(final String containerName, final String key) { public ListenableFuture<Boolean> blobExists(final String containerName, final String key) {
if (!getContainerToBlobs().containsKey(containerName)) if (!storageStrategy.containerExists(containerName))
return immediateFailedFuture(cnfe(containerName)); return immediateFailedFuture(cnfe(containerName));
Map<String, Blob> realContents = getContainerToBlobs().get(containerName); return immediateFuture(storageStrategy.blobExists(containerName, key));
return immediateFuture(realContents.containsKey(key));
} }
/** /**
@ -555,7 +553,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
public ListenableFuture<Blob> getBlob(final String containerName, final String key, GetOptions options) { public ListenableFuture<Blob> getBlob(final String containerName, final String key, GetOptions options) {
logger.debug("Retrieving blob with key %s from container %s", key, containerName); logger.debug("Retrieving blob with key %s from container %s", key, containerName);
// If the container doesn't exist, an exception is thrown // If the container doesn't exist, an exception is thrown
if (!getContainerToBlobs().containsKey(containerName)) { if (!storageStrategy.containerExists(containerName)) {
logger.debug("Container %s does not exist", containerName); logger.debug("Container %s does not exist", containerName);
return immediateFailedFuture(cnfe(containerName)); return immediateFailedFuture(cnfe(containerName));
} }
@ -660,8 +658,8 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
protected boolean deleteAndVerifyContainerGone(final String container) { protected boolean deleteAndVerifyContainerGone(final String container) {
getContainerToBlobs().remove(container); storageStrategy.deleteContainer(container);
return getContainerToBlobs().containsKey(container); return storageStrategy.containerExists(container);
} }
private ConcurrentMap<String, Location> getContainerToLocation() { private ConcurrentMap<String, Location> getContainerToLocation() {
@ -681,4 +679,29 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
throw new UnsupportedOperationException("publicRead"); throw new UnsupportedOperationException("publicRead");
return createContainerInLocation(location, container); return createContainerInLocation(location, container);
} }
private class TransientStorageStrategy {
public Iterable<String> getAllContainerNames() {
return getContainerToBlobs().keySet();
}
public boolean containerExists(final String containerName) {
return getContainerToBlobs().containsKey(containerName);
}
public void deleteContainer(final String containerName) {
getContainerToBlobs().remove(containerName);
}
public boolean blobExists(final String containerName, final String blobName) {
Map<String, Blob> map = containerToBlobs.get(containerName);
return map != null && map.containsKey(blobName);
}
public void removeBlob(final String containerName, final String blobName) {
if (storageStrategy.containerExists(containerName)) {
getContainerToBlobs().get(containerName).remove(blobName);
}
}
}
} }