public class DocumentRevisionTree
extends java.lang.Object
Describes the document tree for a single document within the datastore.
A document within a Datastore
is actually a collection of trees
of revisions. These trees describe the history of the document, and are the
core of the MVCC data model which allows data to be safely replicated
between datastores. Replication consists of copying parts of the tree
in the source database that are not present in the target database to the
target database.
Commonly, there will be a single tree with no branches, just a straight history. This can be represented as follows, abbreviating revision IDs to their generation numbers:
1 → 2 → 3
A full revision ID looks like 1-aedlfksenef
, that is the
generation number combined with an opaque
string which identifies this revision vs other revisions with the same
generation number (see below for when this occurs).
A document can gain branches in its tree. Consider the following sequence of events:
As described above, replication merges the parts of a document tree not in the target datastore into the target datastore. This means we now have a branched tree containing the edits from both A and B:
1 → 2 → 3 → 4 \→ 2^ → 3^
At this point we have a conflicted document: two or more branches terminating in leaf nodes which are not deleted, or active.
In this case, to resolve the conflict the application would need to:
Datastore.getDocument(String, String)
to get the
revisions 4
and 3^
.4
branch using
Datastore.updateDocumentFromRevision(DocumentRevision)
3^
revision using
Datastore.deleteDocumentFromRevision(DocumentRevision)
This process leaves us still with two branches. Because only one terminates in an active leaf, however, the document is no longer conflicted:
1 → 2 → 3 → 4 → 5 \→ 2^ → 3^ → (4^ deleted)
Finally, a document may have multiple document trees. This can happen if a document with the same ID is created in two datastores, and subsequently these two datastores are replicated:
1 → 2 → 3 1* → 2* → 3* → 4* \→ 2^ → 3^
As an aside, this document has three conflicting revisions, which should be resolved as described above.
There can obviously be more than two roots, as a many datastores can replicate together.
At this point, it's possible to note that
this class might better be called DBObjectForest
. However, it's called
DocumentRevisionTree
because Tree is the common terminology used for the
structure inside a document. As each individual tree's first revision is
1-something
, one could think of the document as a single tree with
an implied 0-something
revision at the root.
To construct a DocumentRevisionTree
, first create an empty tree. Then
call add(DocumentRevision)
with each DocumentRevision
in
ascending generation order. For DocumentRevision
s with the same generation,
the order they are added in should not matter; a branch will be created
automatically from the DocumentRevision.getParent()
property of each DocumentRevision
. This implies that if a DocumentRevision
that is not the root of a tree (that is, it has a parent), the parent must
be added first so the tree is constructed correctly.
When a complete tree has been constructed, it's possible to work out things like the complete set of non-deleted leaf revisions (that is, the conflicted revisions for the document) and what is the current winning revision of the document.
Note: This class is not thread safe.
Datastore.resolveConflictsForDocument(String, ConflictResolver)
,
ConflictResolver
Modifier and Type | Class and Description |
---|---|
static class |
DocumentRevisionTree.DocumentRevisionNode
A node in a document's revision tree history.
|
Constructor and Description |
---|
DocumentRevisionTree()
Construct an empty tree.
|
DocumentRevisionTree(DocumentRevision documentRevision)
Construct a tree with a single root.
|
Modifier and Type | Method and Description |
---|---|
DocumentRevisionTree |
add(DocumentRevision documentRevision)
Adds a new
DocumentRevision to the document. |
DocumentRevision |
bySequence(long sequence)
Returns a
DocumentRevision from this DocumentRevisionTree with
a particular sequence number. |
int |
depth(long sequence)
Returns the distance a revision is down the branch it's on.
|
DocumentRevision |
getCurrentRevision()
Returns the
DocumentRevision that is the current winning revision
for this DocumentRevisionTree . |
java.lang.String |
getDocId()
Returns the document ID
|
java.util.List<java.lang.String> |
getPath(long sequence)
Returns the path as a list of revision IDs from the revision with
the given sequence number to the root of the tree containing the
revision.
|
java.util.List<DocumentRevision> |
getPathForNode(long sequence)
Returns the path (list of
DocumentRevision s) from the revision with
the given sequence number to the root of the tree containing the
revision. |
boolean |
hasConflicts()
Returns whether this document is conflicted.
|
java.util.Set<java.lang.String> |
leafRevisionIds()
Returns the revision IDs for the leaf revisions of this document.
|
java.util.List<DocumentRevision> |
leafRevisions()
Returns the leaf revisions
|
java.util.List<DocumentRevision> |
leafRevisions(boolean excludeDeleted)
Returns the leaf revisions
|
java.util.List<DocumentRevisionTree.DocumentRevisionNode> |
leafs()
Returns a list of the
DocumentRevisionTree.DocumentRevisionNode s which are leaf revisions
of the branches in this document |
DocumentRevision |
lookup(java.lang.String id,
java.lang.String rev)
Returns the
DocumentRevision for a document ID and revision ID. |
DocumentRevision |
lookupChildByRevId(DocumentRevision parentNode,
java.lang.String childRevision)
Returns the child with a given revision ID of a parent
DocumentRevision . |
DocumentRevisionTree.DocumentRevisionNode |
root(long sequence)
Returns the root revision of this document with a given sequence number.
|
java.util.Map<java.lang.Long,DocumentRevisionTree.DocumentRevisionNode> |
roots()
Returns the root revisions of this document in a mapping of sequence
number to
DocumentRevisionTree.DocumentRevisionNode . |
public DocumentRevisionTree()
Construct an empty tree.
public DocumentRevisionTree(DocumentRevision documentRevision)
Construct a tree with a single root.
documentRevision
- a root of the revision treepublic DocumentRevisionTree add(DocumentRevision documentRevision)
Adds a new DocumentRevision
to the document.
The DocumentRevision
's parent, if there is one, must already be in
the document tree.
documentRevision
- the DocumentRevision
to addDocumentRevisionTree
for method chainingpublic DocumentRevision lookup(java.lang.String id, java.lang.String rev)
Returns the DocumentRevision
for a document ID and revision ID.
id
- document IDrev
- revision IDDocumentRevision
for the document and revision IDpublic int depth(long sequence)
Returns the distance a revision is down the branch it's on.
sequence
- sequence number to identify the revision-1
if the sequence number isn't present in the document.public DocumentRevision lookupChildByRevId(DocumentRevision parentNode, java.lang.String childRevision)
Returns the child with a given revision ID of a parent
DocumentRevision
.
parentNode
- parent DocumentRevision
childRevision
- revision to look for in child nodesDocumentRevision
.public DocumentRevision bySequence(long sequence)
Returns a DocumentRevision
from this DocumentRevisionTree
with
a particular sequence number.
sequence
- sequence number of the DocumentRevision
DocumentRevision
with the given sequence number,
null if no DocumentRevision
has the given sequence number.public boolean hasConflicts()
Returns whether this document is conflicted.
public java.util.Map<java.lang.Long,DocumentRevisionTree.DocumentRevisionNode> roots()
Returns the root revisions of this document in a mapping of sequence
number to DocumentRevisionTree.DocumentRevisionNode
.
public DocumentRevisionTree.DocumentRevisionNode root(long sequence)
Returns the root revision of this document with a given sequence number.
sequence
- a sequence numberpublic java.util.List<DocumentRevisionTree.DocumentRevisionNode> leafs()
Returns a list of the DocumentRevisionTree.DocumentRevisionNode
s which are leaf revisions
of the branches in this document
DocumentRevisionNode
spublic java.util.Set<java.lang.String> leafRevisionIds()
Returns the revision IDs for the leaf revisions of this document.
public java.util.List<DocumentRevision> leafRevisions()
Returns the leaf revisions
This is the same as calling
leafRevisions(boolean)
with
false
as the parameter
DocumentRevision
objects.public java.util.List<DocumentRevision> leafRevisions(boolean excludeDeleted)
Returns the leaf revisions
excludeDeleted
- if true, exclude deleted leaf revisions from listDocumentRevision
objects.public DocumentRevision getCurrentRevision()
Returns the DocumentRevision
that is the current winning revision
for this DocumentRevisionTree
.
DocumentRevision
that is the current winning revision
for this DocumentRevisionTree
.public java.util.List<DocumentRevision> getPathForNode(long sequence)
Returns the path (list of DocumentRevision
s) from the revision with
the given sequence number to the root of the tree containing the
revision.
The list of revisions is in order of appearance in the tree, where
the first revision is the given DocumentRevision
and the last revision
is the root of the tree.
sequence
- sequence of the starting revisionDocumentRevision
s from the revision with sequence
to the root of the revision's tree.public java.util.List<java.lang.String> getPath(long sequence)
Returns the path as a list of revision IDs from the revision with the given sequence number to the root of the tree containing the revision.
sequence
- sequence of the starting revisionpublic java.lang.String getDocId()