Versioning
Xapiand is distributed. When documents are created, updated, or deleted, the new version of the document has to be replicated to other nodes in the cluster. Xapiand is also asynchronous and concurrent, meaning that these replication requests are sent in parallel, and may arrive at their destination out of sequence. Xapiand needs a way of ensuring that an older version of a document never overwrites a newer version.
To ensure an older version of a document doesn’t overwrite a newer version,
every document has a _version
number that is incremented whenever a document
is changed. Xapiand uses this _version
number to ensure that changes are
applied in the correct order. If an older version of a document arrives after a
new version, it can simply be ignored.
For example, the following indexing command will create a document and assign a version to it:
PUT /twitter/user/Kronuz
{
"name": "Germán Méndez Bravo"
}
This is all business as usual, the interesting bit is in the response:
{
"name": "Germán Méndez Bravo",
"_id": "Kronuz",
"_version": 1
}
Notice the _version
returned when performing an index operation. This is now
the version associated with this particular document. If we get or search for
documents in an index, we will get the version as well.
Optimistic Concurrency Control
Now, the interesting bits can start, as we can use the versioning feature to
perform optimistic concurrency control.
We can take advantage of the _version
number to ensure that conflicting
changes made by our application do not result in data loss. We do this by
specifying the version number of the document that we wish to change. If
that version is no longer current, our request fails.
Let’s create a new blog post:
PUT /blog/1
{
"title": "My first blog entry",
"text": "Just trying this out..."
}
The response body tells us that this newly created document has _version
number 1
. Now imagine that we want to edit the document: we load its data into
a web form, make our changes, and then save the new version.
First we retrieve the document:
GET /blog/1
The response body includes the same _version
number of 1
:
{
"title": "My first blog entry",
"text": "Just trying this out...",
"_id": 1,
"_version": 1
}
Now, when we try to save our changes by reindexing the document, we specify the
version to which our changes should be applied. We want this update to succeed
only if the current _version
of this document in our index is version 1
, so
we pass version=1
as a query param (or _version
as part of the document body):
PUT /blog/1?version=1
{
"title": "My first blog entry",
"text": "Starting to get the hang of this..."
}
This request succeeds, and the response body tells us that the _version
has
been incremented to 2:
{
"title": "My first blog entry",
"text": "Starting to get the hang of this...",
"_id": 1,
"_version": 2
}
However, if we were to rerun the same index request, still specifying
version 1
, Xapiand would respond with a 409 Conflict
HTTP response code.