Skip to content

Commit c7283be

Browse files
committed
Add "history" mode to versioned_writes middleware
This change introduces the concept of a "versioning mode" for versioned_writes. The following modes are supported: * stack When deleting, check whether any previous versions exist in the versions container. If none is found, the object is deleted. If the most-recent version in the versions container is not a delete marker, it is copied into the versioned container (overwriting the current version if one exists) and then deleted from the versions container. This preserves the previous behavior. If the most-recent version in the versions container is a delete marker and a current version exists in the versioned container, the current version is deleted. If the most-recent version in the versions container is a delete marker and no current version exists in the versioned container, we copy the next-most-recent version from the versions container into the versioned container (assuming it exists and is not a delete marker) and delete both the most-recent version (i.e., the delete marker) and the just-copied next-most-recent version from the versions container. With this mode, DELETEs to versioned containers "undo" operations on containers. Previously this was limited to undoing PUTs, but now it will also undo DELETEs performed while in "history" mode. * history When deleting, check whether a current version exists in the versioned container. If one is found, it is copied to the versions container. Then an empty "delete marker" object is also put into the versions container; this records when the object was deleted. Finally, the original current version is deleted from the versioned container. As a result, subsequent GETs or HEADs will return a 404, and container listings for the versioned container do not include the object. With this mode, DELETEs to versioned containers behave like DELETEs to other containers, but with a history of what has happened. Clients may specify (via a new X-Versions-Mode header) which mode a container should use. By default, the existing "stack" mode is used. Upgrade consideration: ====================== Clients should not use the "history" mode until all proxies in the cluster have been upgraded. 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. Change-Id: I555dc17fefd0aa9ade681aa156da24e018ebe74b
1 parent a2c548b commit c7283be

File tree

6 files changed

+934
-144
lines changed

6 files changed

+934
-144
lines changed

api-ref/source/parameters.yaml

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -720,21 +720,24 @@ X-Trans-Id-Extra:
720720
type: string
721721
X-Versions-Location:
722722
description: |
723-
Enables versioning on this container. The value
724-
is the name of another container. You must UTF-8-encode and then
725-
URL-encode the name before you include it in the header. To
726-
disable versioning, set the header to an empty string.
723+
The URL-encoded UTF-8 representation of the container that stores
724+
previous versions of objects. If not set, versioning is disabled
725+
for this container. For more information about object versioning,
726+
see `Object versioning <http://docs.openstack.org/developer/
727+
swift/api/object_versioning.html>`_.
727728
in: header
728729
required: false
729730
type: string
730-
X-Versions-Location_1:
731+
X-Versions-Mode:
731732
description: |
732-
Enables versioning on this container. The value
733-
is the name of another container. You must UTF-8-encode and then
734-
URL-encode the name before you include it in the header. To
735-
disable versioning, set the header to an empty string.
733+
The versioning mode for this container. The value must be either
734+
``stack`` or ``history``. If not set, ``stack`` mode will be used.
735+
This setting has no impact unless ``X-Versions-Location`` is set
736+
for the container. For more information about object versioning,
737+
see `Object versioning <http://docs.openstack.org/developer/
738+
swift/api/object_versioning.html>`_.
736739
in: header
737-
required: true
740+
required: false
738741
type: string
739742

740743
# variables in path

api-ref/source/storage-container-services.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ Request
172172
- X-Container-Sync-To: X-Container-Sync-To
173173
- X-Container-Sync-Key: X-Container-Sync-Key
174174
- X-Versions-Location: X-Versions-Location
175+
- X-Versions-Mode: X-Versions-Mode
175176
- X-Container-Meta-name: X-Container-Meta-name
176177
- X-Container-Meta-Access-Control-Allow-Origin: X-Container-Meta-Access-Control-Allow-Origin
177178
- X-Container-Meta-Access-Control-Max-Age: X-Container-Meta-Access-Control-Max-Age
@@ -302,6 +303,7 @@ Request
302303
- X-Container-Sync-To: X-Container-Sync-To
303304
- X-Container-Sync-Key: X-Container-Sync-Key
304305
- X-Versions-Location: X-Versions-Location
306+
- X-Versions-Mode: X-Versions-Mode
305307
- X-Remove-Versions-Location: X-Remove-Versions-Location
306308
- X-Container-Meta-name: X-Container-Meta-name
307309
- X-Container-Meta-Access-Control-Allow-Origin: X-Container-Meta-Access-Control-Allow-Origin
@@ -409,6 +411,7 @@ Response Parameters
409411
- Content-Type: Content-Type
410412
- X-Container-Meta-Quota-Bytes: X-Container-Meta-Quota-Bytes
411413
- X-Versions-Location: X-Versions-Location
414+
- X-Versions-Mode: X-Versions-Mode
412415

413416

414417

doc/source/api/object_versioning.rst

Lines changed: 177 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ You can store multiple versions of your content so that you can recover
66
from unintended overwrites. Object versioning is an easy way to
77
implement version control, which you can use with any type of content.
88

9-
Note
10-
~~~~
9+
.. note::
10+
You cannot version a large-object manifest file, but the large-object
11+
manifest file can point to versioned segments.
1112

12-
You cannot version a large-object manifest file, but the large-object
13-
manifest file can point to versioned segments.
13+
.. note::
14+
It is strongly recommended that you put non-current objects in a
15+
different container than the container where current object versions
16+
reside.
1417

15-
It is strongly recommended that you put non-current objects in a
16-
different container than the container where current object versions
17-
reside.
18-
19-
To enable object versioning, the cloud provider sets the
20-
``allow_versions`` option to ``TRUE`` in the container configuration
21-
file.
18+
To allow object versioning within a cluster, the cloud provider should add the
19+
``versioned_writes`` filter to the pipeline and set the
20+
``allow_versioned_writes`` option to ``true`` in the
21+
``[filter:versioned_writes]`` section of the proxy-server configuration file.
2222

2323
The ``X-Versions-Location`` header defines the
2424
container that holds the non-current versions of your objects. You
@@ -29,13 +29,21 @@ object versioning for all objects in the container. With a comparable
2929
container automatically create non-current versions in the ``archive``
3030
container.
3131

32-
Here's an example:
32+
The ``X-Versions-Mode`` header defines the behavior of ``DELETE`` requests to
33+
objects in the versioned container. In the default ``stack`` mode, deleting an
34+
object will restore the most-recent version from the ``archive`` container,
35+
overwriting the curent version. Alternatively you may specify ``history``
36+
mode, where deleting an object will copy the current version to the
37+
``archive`` then remove it from the ``current`` container.
38+
39+
Example Using ``stack`` Mode
40+
----------------------------
3341

3442
#. Create the ``current`` container:
3543

3644
.. code::
3745
38-
# curl -i $publicURL/current -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token" -H "X-Versions-Location: archive"
46+
# curl -i $publicURL/current -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token" -H "X-Versions-Location: archive" -H "X-Versions-Mode: stack"
3947
4048
.. code::
4149
@@ -70,7 +78,7 @@ Here's an example:
7078

7179
.. code::
7280
73-
<length><object_name><timestamp>
81+
<length><object_name>/<timestamp>
7482
7583
Where ``length`` is the 3-character, zero-padded hexadecimal
7684
character length of the object, ``<object_name>`` is the object name,
@@ -117,12 +125,10 @@ Here's an example:
117125
118126
009my_object/1390512682.92052
119127
120-
Note
121-
~~~~
122-
123-
A **POST** request to a versioned object updates only the metadata
124-
for the object and does not create a new version of the object. New
125-
versions are created only when the content of the object changes.
128+
.. note::
129+
A **POST** request to a versioned object updates only the metadata
130+
for the object and does not create a new version of the object. New
131+
versions are created only when the content of the object changes.
126132

127133
#. Issue a **DELETE** request to a versioned object to remove the
128134
current version of the object and replace it with the next-most
@@ -163,21 +169,163 @@ Note
163169
on it. If want to completely remove an object and you have five
164170
versions of it, you must **DELETE** it five times.
165171

166-
#. To disable object versioning for the ``current`` container, remove
167-
its ``X-Versions-Location`` metadata header by sending an empty key
168-
value.
172+
Example Using ``history`` Mode
173+
----------------------------
174+
175+
#. Create the ``current`` container:
176+
177+
.. code::
178+
179+
# curl -i $publicURL/current -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token" -H "X-Versions-Location: archive" -H "X-Versions-Mode: history"
180+
181+
.. code::
182+
183+
HTTP/1.1 201 Created
184+
Content-Length: 0
185+
Content-Type: text/html; charset=UTF-8
186+
X-Trans-Id: txb91810fb717347d09eec8-0052e18997
187+
Date: Thu, 23 Jan 2014 21:28:55 GMT
188+
189+
#. Create the first version of an object in the ``current`` container:
190+
191+
.. code::
192+
193+
# curl -i $publicURL/current/my_object --data-binary 1 -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token"
194+
195+
.. code::
196+
197+
HTTP/1.1 201 Created
198+
Last-Modified: Thu, 23 Jan 2014 21:31:22 GMT
199+
Content-Length: 0
200+
Etag: d41d8cd98f00b204e9800998ecf8427e
201+
Content-Type: text/html; charset=UTF-8
202+
X-Trans-Id: tx5992d536a4bd4fec973aa-0052e18a2a
203+
Date: Thu, 23 Jan 2014 21:31:22 GMT
204+
205+
Nothing is written to the non-current version container when you
206+
initially **PUT** an object in the ``current`` container. However,
207+
subsequent **PUT** requests that edit an object trigger the creation
208+
of a version of that object in the ``archive`` container.
209+
210+
These non-current versions are named as follows:
211+
212+
.. code::
213+
214+
<length><object_name>/<timestamp>
215+
216+
Where ``length`` is the 3-character, zero-padded hexadecimal
217+
character length of the object, ``<object_name>`` is the object name,
218+
and ``<timestamp>`` is the time when the object was initially created
219+
as a current version.
220+
221+
#. Create a second version of the object in the ``current`` container:
169222

170223
.. code::
171224
172-
# curl -i $publicURL/current -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token" -H "X-Versions-Location: "
225+
# curl -i $publicURL/current/my_object --data-binary 2 -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token"
173226
174227
.. code::
175228
176-
HTTP/1.1 202 Accepted
177-
Content-Length: 76
229+
HTTP/1.1 201 Created
230+
Last-Modified: Thu, 23 Jan 2014 21:41:32 GMT
231+
Content-Length: 0
232+
Etag: d41d8cd98f00b204e9800998ecf8427e
178233
Content-Type: text/html; charset=UTF-8
179-
X-Trans-Id: txe2476de217134549996d0-0052e19038
180-
Date: Thu, 23 Jan 2014 21:57:12 GMT
234+
X-Trans-Id: tx468287ce4fc94eada96ec-0052e18c8c
235+
Date: Thu, 23 Jan 2014 21:41:32 GMT
236+
237+
#. Issue a **GET** request to a versioned object to get the current
238+
version of the object. You do not have to do any request redirects or
239+
metadata lookups.
240+
241+
List older versions of the object in the ``archive`` container:
242+
243+
.. code::
244+
245+
# curl -i $publicURL/archive?prefix=009my_object -X GET -H "X-Auth-Token: $token"
246+
247+
.. code::
248+
249+
HTTP/1.1 200 OK
250+
Content-Length: 30
251+
X-Container-Object-Count: 1
252+
Accept-Ranges: bytes
253+
X-Timestamp: 1390513280.79684
254+
X-Container-Bytes-Used: 0
255+
Content-Type: text/plain; charset=utf-8
256+
X-Trans-Id: tx9a441884997542d3a5868-0052e18d8e
257+
Date: Thu, 23 Jan 2014 21:45:50 GMT
258+
259+
009my_object/1390512682.92052
260+
261+
.. note::
262+
A **POST** request to a versioned object updates only the metadata
263+
for the object and does not create a new version of the object. New
264+
versions are created only when the content of the object changes.
265+
266+
#. Issue a **DELETE** request to a versioned object to copy the
267+
current version of the object to the archive container then delete it from
268+
the current container. Subsequent **GET** requests to the object in the
269+
current container will return 404 Not Found.
270+
271+
.. code::
272+
273+
# curl -i $publicURL/current/my_object -X DELETE -H "X-Auth-Token: $token"
274+
275+
.. code::
276+
277+
HTTP/1.1 204 No Content
278+
Content-Length: 0
279+
Content-Type: text/html; charset=UTF-8
280+
X-Trans-Id: tx006d944e02494e229b8ee-0052e18edd
281+
Date: Thu, 23 Jan 2014 21:51:25 GMT
282+
283+
List older versions of the object in the ``archive`` container::
284+
285+
.. code::
286+
287+
# curl -i $publicURL/archive?prefix=009my_object -X GET -H "X-Auth-Token: $token"
288+
289+
.. code::
290+
291+
HTTP/1.1 200 OK
292+
Content-Length: 90
293+
X-Container-Object-Count: 3
294+
Accept-Ranges: bytes
295+
X-Timestamp: 1390513280.79684
296+
X-Container-Bytes-Used: 0
297+
Content-Type: text/html; charset=UTF-8
298+
X-Trans-Id: tx044f2a05f56f4997af737-0052e18eed
299+
Date: Thu, 23 Jan 2014 21:51:41 GMT
300+
301+
009my_object/1390512682.92052
302+
009my_object/1390512692.23062
303+
009my_object/1390513885.67732
304+
305+
In addition to the two previous versions of the object, the archive
306+
container has a "delete marker" to record when the object was deleted.
307+
308+
To permanently delete a previous version, issue a **DELETE** to the version
309+
in the archive container.
310+
311+
Disabling Object Versioning
312+
---------------------------
313+
314+
To disable object versioning for the ``current`` container, remove
315+
its ``X-Versions-Location`` metadata header by sending an empty key
316+
value.
317+
318+
.. code::
319+
320+
# curl -i $publicURL/current -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token" -H "X-Versions-Location: "
321+
322+
.. code::
323+
324+
HTTP/1.1 202 Accepted
325+
Content-Length: 76
326+
Content-Type: text/html; charset=UTF-8
327+
X-Trans-Id: txe2476de217134549996d0-0052e19038
328+
Date: Thu, 23 Jan 2014 21:57:12 GMT
181329
182-
<html><h1>Accepted</h1><p>The request is accepted for processing.</p></html>
330+
<html><h1>Accepted</h1><p>The request is accepted for processing.</p></html>
183331

0 commit comments

Comments
 (0)