Search code examples
openstackrackspace-cloudrackspace

[OpenStack .NET API]: Is there a way to combine the Object creation and Container creation in one call?


Currently I do this

try
{
    cloudFilesProvider.CreateObjectFromFile(inStrContainerName, inStrSrcFilePath, strDesFileName, 4096, FileMetaData);

}
catch (ItemNotFoundException ex1)
{
     try
     {
         cloudFilesProvider.CreateContainer(inStrContainerName);
         cloudFilesProvider.CreateObjectFromFile(inStrContainerName, inStrSrcFilePath, strDesFileName, 4096, FileMetaData);
     }
     catch(Exception ex2)
     {
         return false;
     }
}

So essentially if the container does not exist then its 3 separate API calls.

Is there a more efficient way to do this?


Solution

  • You can simplify the code by reducing it to the following two lines.

    cloudFilesProvider.CreateContainer(inStrContainerName);
    cloudFilesProvider.CreateObjectFromFile(inStrContainerName, inStrSrcFilePath, strDesFileName, 4096, FileMetaData);
    

    CreateContainer is safe to call for a container that already exists. It returns ContainerCreated if the container is created, or ContainerExists if the container was not created because it already exists.

    PS: The return values (with information like the above) for the IObjectStorageProvider methods will be well documented for release 1.2.0.0.


    Edit: To reduce the number of API calls your code makes, you could use a cache class like the following. The CreateIfNecessary method attempts to create the container only if it is not previously known to exist. The ClearCache method provides a manual method for continuing to use the cache even if you delete a container.

    This code is currently untested.

    public class ContainerManager
    {
        private readonly CloudFilesProvider _provider;
        private readonly string _region;
        private readonly bool _useInternalUrl;
        private readonly CloudIdentity _identity;
    
        private readonly HashSet<string> _containers = new HashSet<string>();
    
        public ContainerManager(CloudFilesProvider provider, string region, bool useInternalUrl, CloudIdentity identity)
        {
            if (provider == null)
                throw new ArgumentNullException("provider");
    
            _provider = provider;
            _region = region;
            _useInternalUrl = useInternalUrl;
            _identity = identity;
        }
    
        /// <summary>
        /// Clears the cache of known containers.
        /// </summary>
        /// <remarks>
        /// <alert class="warning">
        /// If a container was deleted after this cache was in use, this method must be called or
        /// <see cref="CreateIfNecessary(string)"/> could fail to create a container which does not
        /// exist.
        /// </alert>
        /// </remarks>
        public void ClearCache()
        {
            lock (_containers)
            {
                _containers.Clear();
            }
        }
    
        /// <summary>
        /// Ensures that a container exists in the Cloud Files store.
        /// </summary>
        /// <remarks>
        /// <alert class="warning">
        /// If a container was deleted after this cache was in use, and <see cref="ClearCache()"/>
        /// has not been called, this method could fail to create a container which does not exist.
        /// </alert>
        /// </remarks>
        /// <param name="container">The name of the container to create.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="container"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">If <paramref name="container"/> is empty.</exception>
        /// <returns><c>true</c> if the container was created; otherwise <c>false</c> if the container already existed.</returns>
        public bool CreateIfNecessary(string container)
        {
            if (container == null)
                throw new ArgumentNullException("container");
            if (string.IsNullOrEmpty(container))
                throw new ArgumentException("container cannot be empty");
    
            // don't try to create the same container multiple times
            if (_containers.Contains(container))
                return false;
    
            ObjectStore result = _provider.CreateContainer(container, _region, _useInternalUrl, _identity);
            if (result == ObjectStore.ContainerCreated || result == ObjectStore.ContainerExists)
            {
                lock (_containers)
                {
                    // add to _containers even if the result is ContainerExists, because that
                    // means it simply wasn't known to this cache.
                    _containers.Add(container);
                }
            }
    
            // only return true if the container was actually created
            return result == ObjectStore.ContainerCreated;
        }
    }