Object Versioning

Object versioning in swift is implemented by setting a flag on the container to tell swift to version all objects in the container. The flag is the X-Versions-Location header on the container, and its value is the container where the versions are stored.

Note

It is recommended to use a different X-Versions-Location container for each container that is being versioned.

When data is PUT into a versioned container (a container with the versioning flag turned on), the existing data in the file is redirected to a new object and the data in the PUT request is saved as the data for the versioned object. The new object name (for the previous version) is <archive_container>/<length><object_name>/<timestamp>, where length is the 3-character zero-padded hexadecimal length of the <object_name> and <timestamp> is the timestamp of when the previous version was created.

A GET to a versioned object will return the current version of the object without having to do any request redirects or metadata lookups.

A POST to a versioned object will update the object metadata as normal, but will not create a new version of the object. In other words, new versions are only created when the content of the object changes.

A DELETE to a versioned object will be handled in one of two ways, depending on the value of a X-Versions-Mode header set on the container. The available modes are:

  • stack

    Only remove the current version of the object. If any previous versions exist in the archive container, the most recent one is copied over the current version, and the copy in the archive container is deleted. As a result, if you have 5 total versions of the object, you must delete the object 5 times to completely remove the object. This is the default behavior if X-Versions-Mode has not been set for the container.

  • history

    Copy the current version of the object to the archive container, write a zero-byte “delete marker” object that notes when the delete took place, and delete the object from the versioned container. The object will no longer appear in container listings for the versioned container and future requests there will return 404 Not Found. However, the content will still be recoverable from the archive container.

Note

While it is possible to switch between ‘stack’ and ‘history’ mode on a container, it is not recommended.

To restore a previous version of an object, find the desired version in the archive container then issue a COPY with a Destination header indicating the original location. This will retain a copy of the current version similar to a PUT over the versioned object. Additionally, if the container is in stack mode and the client wishes to permanently delete the current version, it may issue a DELETE to the versioned object as described above.

How to Enable Object Versioning in a Swift Cluster

This middleware was written as an effort to refactor parts of the proxy server, so this functionality was already available in previous releases and every attempt was made to maintain backwards compatibility. To allow operators to perform a seamless upgrade, it is not required to add the middleware to the proxy pipeline and the flag allow_versions in the container server configuration files are still valid. In future releases, allow_versions will be deprecated in favor of adding this middleware to the pipeline to enable or disable the feature.

In case the middleware is added to the proxy pipeline, you must also set allow_versioned_writes to True in the middleware options to enable the information about this middleware to be returned in a /info request.

Upgrade considerations:

If allow_versioned_writes is set in the filter configuration, you can leave the allow_versions flag in the container server configuration files untouched. If you decide to disable or remove the allow_versions flag, you must re-set any existing containers that had the ‘X-Versions-Location’ flag configured so that it can now be tracked by the versioned_writes middleware.

Clients should not use the ‘history’ mode until all proxies in the cluster have been upgraded to a version of Swift that supports it. Attempting to use the ‘history’ mode during a rolling upgrade may result in some requests being served by proxies running old code (which necessarily uses the ‘stack’ mode), leading to data loss.

Examples Using curl with stack Mode

First, create a container with the X-Versions-Location header or add the header to an existing container. Also make sure the container referenced by the X-Versions-Location exists. In this example, the name of that container is “versions”:

curl -i -XPUT -H "X-Auth-Token: <token>" -H "X-Versions-Mode: stack" -H "X-Versions-Location: versions" http://<storage_url>/container
curl -i -XPUT -H "X-Auth-Token: <token>" http://<storage_url>/versions

Create an object (the first version):

curl -i -XPUT --data-binary 1 -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject

Now create a new version of that object:

curl -i -XPUT --data-binary 2 -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject

See a listing of the older versions of the object:

curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/

Now delete the current version of the object and see that the older version is gone from ‘versions’ container and back in ‘container’ container:

curl -i -XDELETE -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/
curl -i -XGET -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject

Examples Using curl with history Mode

As above, create a container with the X-Versions-Location header and ensure that the container referenced by the X-Versions-Location exists. In this example, the name of that container is “versions”:

curl -i -XPUT -H "X-Auth-Token: <token>" -H "X-Versions-Mode: history" -H "X-Versions-Location: versions" http://<storage_url>/container
curl -i -XPUT -H "X-Auth-Token: <token>" http://<storage_url>/versions

Create an object (the first version):

curl -i -XPUT --data-binary 1 -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject

Now create a new version of that object:

curl -i -XPUT --data-binary 2 -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject

Now delete the current version of the object. Subsequent requests will 404:

curl -i -XDELETE -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
curl -i -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject

A listing of the older versions of the object will include both the first and second versions of the object, as well as a “delete marker” object:

curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/

To restore a previous version, simply COPY it from the archive container:

curl -i -XCOPY -H "X-Auth-Token: <token>" http://<storage_url>/versions/008myobject/<timestamp> -H "Destination: container/myobject"

Note that the archive container still has all previous versions of the object, including the source for the restore:

curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/

To permanently delete a previous version, DELETE it from the archive container:

curl -i -XDELETE -H "X-Auth-Token: <token>" http://<storage_url>/versions/008myobject/<timestamp> 

How to Disable Object Versioning in a Swift Cluster

If you want to disable all functionality, set allow_versioned_writes to False in the middleware options.

Disable versioning from a container (x is any value except empty):

curl -i -XPOST -H "X-Auth-Token: <token>" -H "X-Remove-Versions-Location: x" http://<storage_url>/container