Not sure I follow. If a transaction needs the full revision tree for a single 
document it can retrieve that with a single range read for the (“_meta”, DocID) 
prefix.

Adam

> On Feb 8, 2019, at 6:35 PM, Paul Davis <paul.joseph.da...@gmail.com> wrote:
> 
> Ah, that all sounds good. The only thing I'm not initially seeing as
> obvious is how we lookup a revision path to extend during replication
> when the previous revision may be anywhere in the list of $revs_limit
> revisions. Feels like there might be some sort of trickery to do that
> efficiently. Although it may also be good enough to also just issue
> $revs_limit lookups in parallel given that we're maxed out on either
> $revs_limit or 2*$revs_limit if we have to check for both deleted and
> not.
> 
> On Fri, Feb 8, 2019 at 10:22 AM Adam Kocoloski <kocol...@apache.org> wrote:
>> 
>> Totally unacceptable! ;)  In fact some key bits of that model got dispersed 
>> into at least two separate emails so you’re likely not the only one. I’ll 
>> restate here:
>> 
>> The size limits in FoundationDB preclude us from storing the entire key tree 
>> as a single value; in pathological situations the tree could exceed 100KB. 
>> Rather, I think it would make sense to store each edit *branch* as a 
>> separate KV. We stem the branch long before it hits the value size limit, 
>> and in the happy case of no edit conflicts this means we store the edit 
>> history metadata in a single KV. It also means that we can apply an 
>> interactive edit without retrieving the entire conflicted revision tree; we 
>> need only retrieve and modify the single branch against which the edit is 
>> being applied. The downside is that we may duplicate historical revision 
>> identifiers shared by multiple edit branches, but I think this is a 
>> worthwhile tradeoff.
>> 
>> I’d also ensure that a document update only needs to read the edit branch KV 
>> against which the update is being applied, and it can read that branch 
>> immediately knowing only the content of the edit that is being attempted 
>> (i.e., it does not need to read the current version of the document itself).
>> 
>> I think we achieve these goals with a separate subspace (maybe “_meta”?) for 
>> the revision trees, with keys and values that look like
>> 
>> (“_meta”, DocID, NotDeleted, RevPosition, RevHash) = 
>> (VersionstampForCurrentRev, [ParentRev, GrandparentRev, …])
>> 
>> Some notes:
>> 
>> - including IsDeleted ensures that we can efficiently accept the case where 
>> we upload a new document with the same ID where all previous edit branches 
>> have been deleted; i.e. we can construct a key selector which automatically 
>> tells us there are no deleted=false edit branches
>> - access to VersionstampForCurrentRev ensures we can clear the old entry in 
>> the by_seq space during the update
>> - i need to remind myself how we handle an edit attempt which supplies a 
>> _rev representing a deleted leaf. Do we fail that as a conflict? That would 
>> be the natural thing to do here, otherwise we’re forced to check both 
>> deleted=false and deleted=true keys
>> - the keys can be made to naturally sort so that the winning revision sorts 
>> last, but I don’t believe that’s a requirement here like it is for the 
>> actual document data space
>> 
>> Cheers, Adam
>> 
>>> On Feb 8, 2019, at 8:59 AM, Paul Davis <paul.joseph.da...@gmail.com> wrote:
>>> 
>>>> I’m relatively happy with the revision history data model at this point.
>>> 
>>> I forgot to make a note, but which of the various models are you
>>> referring to by "revision history data model". There's been so many
>>> without firm names that my brain is having a hard time parsing that
>>> one.
>>> 
>>> On Thu, Feb 7, 2019 at 9:35 PM Adam Kocoloski <kocol...@apache.org> wrote:
>>>> 
>>>> Bob, Garren, Jan - heard you loud and clear, K.I.S.S. I do think it’s a 
>>>> bit “simplistic" to exclusively choose simplicity over performance and 
>>>> storage density. We’re (re)building a database here, one that has some 
>>>> users with pretty demanding performance and scalability requirements. And 
>>>> yes, we should certainly be testing and measuring. Kyle and team are 
>>>> setting up infrastructure in IBM land to help with that now, but I also 
>>>> believe we can design the data model and architecture with a basic 
>>>> performance model of FoundationDB in mind:
>>>> 
>>>> - reads cost 1ms
>>>> - short range reads are the same cost as a single lookup
>>>> - reads of independent parts of the keyspace can be parallelized for cheap
>>>> - writes are zero-cost until commit time
>>>> 
>>>> We ought to be able to use these assumptions to drive some decisions about 
>>>> data models ahead of any end-to-end performance test.
>>>> 
>>>> If there are specific elements of the edit conflicts management where you 
>>>> think greater simplicity is warranted, let’s get those called out. Ilya 
>>>> noted (correctly, in my opinion) that the term sharing stuff is one of 
>>>> those items. It’s relatively complex, potentially a performance hit, and 
>>>> only saves on storage density in the corner case of lots of edit 
>>>> conflicts. That’s a good one to drop.
>>>> 
>>>> I’m relatively happy with the revision history data model at this point. 
>>>> Hopefully folks find it easy to grok, and it’s efficient for both reads 
>>>> and writes. It costs some extra storage for conflict revisions compared to 
>>>> the current tree representation (up to 16K per edit branch, with default 
>>>> _revs_limit) but knowing what we know about the performance death spiral 
>>>> for wide revision trees today I’ll happily make a storage vs. performance 
>>>> tradeoff here :)
>>>> 
>>>> Setting the shared term approach aside, I’ve still been mulling over the 
>>>> key structure for the actual document data:
>>>> 
>>>> -  I thought about trying to construct a special _conflicts subspace, but 
>>>> I don’t like that approach because the choice of a “winning" revision can 
>>>> flip back and forth very quickly with concurrent writers to different edit 
>>>> branches. I think we really want to have a way for revisions to naturally 
>>>> sort themselves so the winner is the first or last revision in a list.
>>>> 
>>>> - Assuming we’re using key paths of the form (docid, revision-ish, path, 
>>>> to, field), the goal here is to find an efficient way to get the last key 
>>>> with prefix “docid” (assuming winner sorts last), and then all the keys 
>>>> that share the same (docid, revision-ish) prefix as that one. I see two 
>>>> possible approaches so far, neither perfect:
>>>> 
>>>> Option 1: Execute a get_key() operation with a key selector that asks for 
>>>> the last key less than “docid\xFF” (again assuming winner sorts last), and 
>>>> then do a get_range_startswith() request setting the streaming mode to 
>>>> “want_all” and the prefix to the docid plus whatever revision-ish we found 
>>>> from the get_key() request. This is two roundtrips instead of one, but it 
>>>> always retrieves exactly the right set of keys, and the second step is 
>>>> executed as fast as possible.
>>>> 
>>>> Option 2: Jump straight to get_range_startswith() request using only 
>>>> “docid” as the prefix, then cancel the iteration once we reach a revision 
>>>> not equal to the first one we see. We might transfer too much data, or we 
>>>> might end up doing multiple roundtrips if the default “iterator” streaming 
>>>> mode sends too little data to start (I haven’t checked what the default 
>>>> iteration block is there), but in the typical case of zero edit conflicts 
>>>> we have a good chance of retrieving the full document in one roundtrip.
>>>> 
>>>> I don’t have a good sense of which option wins out here from a performance 
>>>> perspective, but they’re both operating on the same data model so easy 
>>>> enough to test the alternatives. The important bit is getting the 
>>>> revision-ish things to sort correctly. I think we can do that by 
>>>> generating something like
>>>> 
>>>> revision-ish = NotDeleted/1bit : RevPos : RevHash
>>>> 
>>>> with some suitable order-preserving encoding on the RevPos integer.
>>>> 
>>>> Apologies for the long email. Happy for any comments, either here or over 
>>>> on IRC. Cheers,
>>>> 
>>>> Adam
>>>> 
>>>>> On Feb 7, 2019, at 4:52 PM, Robert Newson <rnew...@apache.org> wrote:
>>>>> 
>>>>> I think we should choose simple. We can then see if performance is too 
>>>>> low or storage overhead too high and then see what we can do about it.
>>>>> 
>>>>> B.
>>>>> 
>>>>> --
>>>>> Robert Samuel Newson
>>>>> rnew...@apache.org
>>>>> 
>>>>> On Thu, 7 Feb 2019, at 20:36, Ilya Khlopotov wrote:
>>>>>> We cannot do simple thing if we want to support sharing of JSON terms. I
>>>>>> think if we want the simplest path we should move sharing out of the
>>>>>> scope. The problem with sharing is we need to know the location of
>>>>>> shared terms when we do write. This means that we have to read full
>>>>>> document on every write. There might be tricks to replace full document
>>>>>> read with some sort of hierarchical signature or sketch of a document.
>>>>>> However these tricks do not fall into simplest solution category. We
>>>>>> need to choose the design goals:
>>>>>> - simple
>>>>>> - performance
>>>>>> - reduced storage overhead
>>>>>> 
>>>>>> best regards,
>>>>>> iilyak
>>>>>> 
>>>>>> On 2019/02/07 12:45:34, Garren Smith <gar...@apache.org> wrote:
>>>>>>> I’m also in favor of keeping it really simple and then testing and
>>>>>>> measuring it.
>>>>>>> 
>>>>>>> What is the best way to measure that we have something that works? I’m 
>>>>>>> not
>>>>>>> sure just relying on our current tests will prove that? Should we define
>>>>>>> and build some more complex situations e.g docs with lots of conflicts 
>>>>>>> or
>>>>>>> docs with wide revisions and make sure we can solve for those?
>>>>>>> 
>>>>>>> On Thu, Feb 7, 2019 at 12:33 PM Jan Lehnardt <j...@apache.org> wrote:
>>>>>>> 
>>>>>>>> I’m also very much in favour with starting with the simplest thing that
>>>>>>>> can possibly work and doesn’t go against the advertised best practices 
>>>>>>>> of
>>>>>>>> FoundationDB. Let’s get that going and get a feel for how it all works
>>>>>>>> together, before trying to optimise things we can’t measure yet.
>>>>>>>> 
>>>>>>>> Best
>>>>>>>> Jan
>>>>>>>> —
>>>>>>>> 
>>>>>>>>> On 6. Feb 2019, at 16:58, Robert Samuel Newson <rnew...@apache.org>
>>>>>>>> wrote:
>>>>>>>>> 
>>>>>>>>> Hi,
>>>>>>>>> 
>>>>>>>>> With the Redwood storage engine under development and with prefix
>>>>>>>> elision part of its design, I don’t think we should get too hung up on
>>>>>>>> adding complications and indirections in the key space just yet. We 
>>>>>>>> haven’t
>>>>>>>> written a line of code or run any tests, this is premature 
>>>>>>>> optimisation.
>>>>>>>>> 
>>>>>>>>> I’d like to focus on the simplest solution that yields all required
>>>>>>>> properties. We can embellish later (if warranted).
>>>>>>>>> 
>>>>>>>>> I am intrigued by all the ideas that might allow us cheaper inserts 
>>>>>>>>> and
>>>>>>>> updates than the current code where there are multiple edit branches 
>>>>>>>> in the
>>>>>>>> stored document.
>>>>>>>>> 
>>>>>>>>> B.
>>>>>>>>> 
>>>>>>>>>> On 6 Feb 2019, at 02:18, Ilya Khlopotov <iil...@apache.org> wrote:
>>>>>>>>>> 
>>>>>>>>>> While reading Adam's proposal I came to realize that: we don't have 
>>>>>>>>>> to
>>>>>>>> calculate winning revision at read time.
>>>>>>>>>> Since FDB's transactions are atomic we can calculate it when we 
>>>>>>>>>> write.
>>>>>>>> This means we can just write latest values into separate range. This 
>>>>>>>> makes
>>>>>>>> lookup of latest version fast.
>>>>>>>>>> Another realization is if we want to share values for some json paths
>>>>>>>> we would have to introduce a level of indirection.
>>>>>>>>>> Bellow is the data model inspired by Adam's idea to share json_paths.
>>>>>>>> In this model the json_path is stored in the revision where it was 
>>>>>>>> first
>>>>>>>> added (we call that revision an owner of a json_path). The values for
>>>>>>>> json_path key can be scalar values, parts of scalar values or pointers 
>>>>>>>> to
>>>>>>>> owner location.
>>>>>>>>>> The below snippets are sketches of transactions.
>>>>>>>>>> The transactions will include updates to other keys as needed
>>>>>>>> (`external_size`, `by_seq` and so on).  The revision tree management 
>>>>>>>> is not
>>>>>>>> covered yet.
>>>>>>>>>> The `rev -> vsn` indirection is not strictly required. It is added
>>>>>>>> because it saves some space since `rev` is a long string and `vsn` is 
>>>>>>>> FDB
>>>>>>>> versionstamp of fixed size.
>>>>>>>>>> 
>>>>>>>>>> - `{NS} / {docid} / _by_rev / {rev} = vsn`
>>>>>>>>>> - `{NS} / {docid} / _used_by / {json_path} / {another_vsn} = NIL`
>>>>>>>>>> - `{NS} / {docid} / _data / {json_path} = latest_value | part`
>>>>>>>>>> - `{NS} / {docid} / {vsn} / _data / {json_path} = value | part |
>>>>>>>> {another_vsn}`
>>>>>>>>>> 
>>>>>>>>>> ```
>>>>>>>>>> write(txn, doc_id, prev_rev, json):
>>>>>>>>>> txn.add_write_conflict_key("{NS} / {doc_id} / _rev")
>>>>>>>>>> rev = generate_new_rev()
>>>>>>>>>> txn["{NS} / {docid} / _by_rev / {rev}"] = vsn
>>>>>>>>>> for every json_path in flattened json
>>>>>>>>>> - {NS} / {docid} / _used_by / {json_path} / {another_vsn} = NIL
>>>>>>>>>> if rev is HEAD:
>>>>>>>>>>   # this range contains values for all json paths for the latest
>>>>>>>> revision (read optimization)
>>>>>>>>>>   - {NS} / {docid} / _data / {json_path} = latest_value | part
>>>>>>>>>> - {NS} / {docid} / {vsn} / _data / {json_path} = value | part |
>>>>>>>> {another_vsn}
>>>>>>>>>> txn["{NS} / {doc_id} / _rev"] = rev
>>>>>>>>>> 
>>>>>>>>>> get_current(txn, doc_id):
>>>>>>>>>> # there is no sharing of json_paths in this range (read optimization)
>>>>>>>>>> txn.get_range("{NS} / {docid} / _data / 0x00", "{NS} / {docid} / 
>>>>>>>>>> _data
>>>>>>>> / 0xFF" )
>>>>>>>>>> 
>>>>>>>>>> get_revision(txn, doc_id, rev):
>>>>>>>>>> vsn = txn["{NS} / {docid} / _by_rev / {rev}"]
>>>>>>>>>> json_paths = txn.get_range("{NS} / {vsn} / {docid} / _data / 0x00",
>>>>>>>> "{NS} / {vsn} / {docid} / _data / 0xFF" )
>>>>>>>>>> for every json_path in json_paths:
>>>>>>>>>> if value has type vsn:
>>>>>>>>>>   another_vsn = value
>>>>>>>>>>      value = txn["{NS} / {docid} / {another_vsn} / _data /
>>>>>>>> {json_path}"]
>>>>>>>>>> result[json_path] = value
>>>>>>>>>> 
>>>>>>>>>> delete_revision(txn, doc_id, rev):
>>>>>>>>>> vsn = txn["{NS} / {docid} / _by_rev / {rev}"]
>>>>>>>>>> json_paths = txn.get_range("{NS} / {vsn} / {docid} / _data / 0x00",
>>>>>>>> "{NS} / {vsn} / {docid} / _data / 0xFF" )
>>>>>>>>>> for every json_path in json_paths:
>>>>>>>>>> if value has type vsn:
>>>>>>>>>>  # remove reference to deleted revision from the owner
>>>>>>>>>>   del txn[{NS} / {docid} / _used_by / {json_path} / {vsn}]
>>>>>>>>>> # check if deleted revision of json_path is not used by anything else
>>>>>>>>>> if txn.get_range("{NS} / {docid} / _used_by / {json_path} / {vsn}",
>>>>>>>> limit=1) == []:
>>>>>>>>>>   del txn["{NS} / {docid} / {vsn} / _data / {json_path}"]
>>>>>>>>>> if vsn is HEAD:
>>>>>>>>>>   copy range for winning revision into "{NS} / {docid} / _data /
>>>>>>>> {json_path}"
>>>>>>>>>> ```
>>>>>>>>>> 
>>>>>>>>>> best regards,
>>>>>>>>>> iilyak
>>>>>>>>>> 
>>>>>>>>>> On 2019/02/04 23:22:09, Adam Kocoloski <kocol...@apache.org> wrote:
>>>>>>>>>>> I think it’s fine to start a focused discussion here as it might 
>>>>>>>>>>> help
>>>>>>>> inform some of the broader debate over in that thread.
>>>>>>>>>>> 
>>>>>>>>>>> As a reminder, today CouchDB writes the entire body of each document
>>>>>>>> revision on disk as a separate blob. Edit conflicts that have common 
>>>>>>>> fields
>>>>>>>> between them do not share any storage on disk. The revision tree is 
>>>>>>>> encoded
>>>>>>>> into a compact format and a copy of it is stored directly in both the 
>>>>>>>> by_id
>>>>>>>> tree and the by_seq tree. Each leaf entry in the revision tree contain 
>>>>>>>> a
>>>>>>>> pointer to the position of the associated doc revision on disk.
>>>>>>>>>>> 
>>>>>>>>>>> As a further reminder, CouchDB 2.x clusters can generate edit 
>>>>>>>>>>> conflict
>>>>>>>> revisions just from multiple clients concurrently updating the same
>>>>>>>> document in a single cluster. This won’t happen when FoundationDB is
>>>>>>>> running under the hood, but users who deploy multiple CouchDB or 
>>>>>>>> PouchDB
>>>>>>>> servers and replicate between them can of course still produce 
>>>>>>>> conflicts
>>>>>>>> just like they could in CouchDB 1.x, so we need a solution.
>>>>>>>>>>> 
>>>>>>>>>>> Let’s consider the two sub-topics separately: 1) storage of edit
>>>>>>>> conflict bodies and 2) revision trees
>>>>>>>>>>> 
>>>>>>>>>>> ## Edit Conflict Storage
>>>>>>>>>>> 
>>>>>>>>>>> The simplest possible solution would be to store each document
>>>>>>>> revision separately, like we do today. We could store document bodies 
>>>>>>>> with
>>>>>>>> (“docid”, “revid”) as the key prefix, and each transaction could clear 
>>>>>>>> the
>>>>>>>> key range associated with the base revision against which the edit is 
>>>>>>>> being
>>>>>>>> attempted. This would work, but I think we can try to be a bit more 
>>>>>>>> clever
>>>>>>>> and save on storage space given that we’re splitting JSON documents 
>>>>>>>> into
>>>>>>>> multiple KV pairs.
>>>>>>>>>>> 
>>>>>>>>>>> One thought I’d had is to introduce a special enum Value which
>>>>>>>> indicates that the subtree “beneath” the given Key is in conflict. For
>>>>>>>> example, consider the documents
>>>>>>>>>>> 
>>>>>>>>>>> {
>>>>>>>>>>> “_id”: “foo”,
>>>>>>>>>>> “_rev”: “1-abc”,
>>>>>>>>>>> “owner”: “alice”,
>>>>>>>>>>> “active”: true
>>>>>>>>>>> }
>>>>>>>>>>> 
>>>>>>>>>>> and
>>>>>>>>>>> 
>>>>>>>>>>> {
>>>>>>>>>>> “_id”: “foo”,
>>>>>>>>>>> “_rev”: “1-def”,
>>>>>>>>>>> “owner”: “bob”,
>>>>>>>>>>> “active”: true
>>>>>>>>>>> }
>>>>>>>>>>> 
>>>>>>>>>>> We could represent these using the following set of KVs:
>>>>>>>>>>> 
>>>>>>>>>>> (“foo”, “active”) = true
>>>>>>>>>>> (“foo”, “owner”) = kCONFLICT
>>>>>>>>>>> (“foo”, “owner”, “1-abc”) = “alice”
>>>>>>>>>>> (“foo”, “owner”, “1-def”) = “bob”
>>>>>>>>>>> 
>>>>>>>>>>> This approach also extends to conflicts where the two versions have
>>>>>>>> different data types. Consider a more complicated example where bob 
>>>>>>>> dropped
>>>>>>>> the “active” field and changed the “owner” field to an object:
>>>>>>>>>>> 
>>>>>>>>>>> {
>>>>>>>>>>> “_id”: “foo”,
>>>>>>>>>>> “_rev”: “1-def”,
>>>>>>>>>>> “owner”: {
>>>>>>>>>>> “name”: “bob”,
>>>>>>>>>>> “email”: “b...@example.com"
>>>>>>>>>>> }
>>>>>>>>>>> }
>>>>>>>>>>> 
>>>>>>>>>>> Now the set of KVs for “foo” looks like this (note that a missing
>>>>>>>> field needs to be handled explicitly):
>>>>>>>>>>> 
>>>>>>>>>>> (“foo”, “active”) = kCONFLICT
>>>>>>>>>>> (“foo”, “active”, “1-abc”) = true
>>>>>>>>>>> (“foo”, “active”, “1-def”) = kMISSING
>>>>>>>>>>> (“foo”, “owner”) = kCONFLICT
>>>>>>>>>>> (“foo”, “owner”, “1-abc”) = “alice”
>>>>>>>>>>> (“foo”, “owner”, “1-def”, “name”) = “bob”
>>>>>>>>>>> (“foo”, “owner”, “1-def”, “email”) = “b...@example.com”
>>>>>>>>>>> 
>>>>>>>>>>> I like this approach for the common case where documents share most 
>>>>>>>>>>> of
>>>>>>>> their data in common but have a conflict in a very specific field or 
>>>>>>>> set of
>>>>>>>> fields.
>>>>>>>>>>> 
>>>>>>>>>>> I’ve encountered one important downside, though: an edit that
>>>>>>>> replicates in and conflicts with the entire document can cause a bit 
>>>>>>>> of a
>>>>>>>> data explosion. Consider a case where I have 10 conflicting versions 
>>>>>>>> of a
>>>>>>>> 100KB document, but the conflicts are all related to a single scalar 
>>>>>>>> value.
>>>>>>>> Now I replicate in an empty document, and suddenly I have a kCONFLICT 
>>>>>>>> at
>>>>>>>> the root. In this model I now need to list out every path of every one 
>>>>>>>> of
>>>>>>>> the 10 existing revisions and I end up with a 1MB update. Yuck. That’s
>>>>>>>> technically no worse in the end state than the “zero sharing” case 
>>>>>>>> above,
>>>>>>>> but one could easily imagine overrunning the transaction size limit 
>>>>>>>> this
>>>>>>>> way.
>>>>>>>>>>> 
>>>>>>>>>>> I suspect there’s a smart path out of this. Maybe the system 
>>>>>>>>>>> detects a
>>>>>>>> “default” value for each field and uses that instead of writing out the
>>>>>>>> value for every revision in a conflicted subtree. Worth some 
>>>>>>>> discussion.
>>>>>>>>>>> 
>>>>>>>>>>> ## Revision Trees
>>>>>>>>>>> 
>>>>>>>>>>> In CouchDB we currently represent revisions as a hash history tree;
>>>>>>>> each revision identifier is derived from the content of the revision
>>>>>>>> including the revision identifier of its parent. Individual edit 
>>>>>>>> branches
>>>>>>>> are bounded in *length* (I believe the default is 1000 entries), but 
>>>>>>>> the
>>>>>>>> number of edit branches is technically unbounded.
>>>>>>>>>>> 
>>>>>>>>>>> The size limits in FoundationDB preclude us from storing the entire
>>>>>>>> key tree as a single value; in pathological situations the tree could
>>>>>>>> exceed 100KB. Rather, I think it would make sense to store each edit
>>>>>>>> *branch* as a separate KV. We stem the branch long before it hits the 
>>>>>>>> value
>>>>>>>> size limit, and in the happy case of no edit conflicts this means we 
>>>>>>>> store
>>>>>>>> the edit history metadata in a single KV. It also means that we can 
>>>>>>>> apply
>>>>>>>> an interactive edit without retrieving the entire conflicted revision 
>>>>>>>> tree;
>>>>>>>> we need only retrieve and modify the single branch against which the 
>>>>>>>> edit
>>>>>>>> is being applied. The downside is that we duplicate historical revision
>>>>>>>> identifiers shared by multiple edit branches, but I think this is a
>>>>>>>> worthwhile tradeoff.
>>>>>>>>>>> 
>>>>>>>>>>> I would furthermore try to structure the keys so that it is possible
>>>>>>>> to retrieve the “winning” revision in a single limit=1 range query. 
>>>>>>>> Ideally
>>>>>>>> I’d like to proide the following properties:
>>>>>>>>>>> 
>>>>>>>>>>> 1) a document read does not need to retrieve the revision tree at 
>>>>>>>>>>> all,
>>>>>>>> just the winning revision identifier (which would be stored with the 
>>>>>>>> rest
>>>>>>>> of the doc)
>>>>>>>>>>> 2) a document update only needs to read the edit branch of the
>>>>>>>> revision tree against which the update is being applied, and it can 
>>>>>>>> read
>>>>>>>> that branch immediately knowing only the content of the edit that is 
>>>>>>>> being
>>>>>>>> attempted (i.e., it does not need to read the current version of the
>>>>>>>> document itself).
>>>>>>>>>>> 
>>>>>>>>>>> So, I’d propose a separate subspace (maybe “_meta”?) for the 
>>>>>>>>>>> revision
>>>>>>>> trees, with keys and values that look like
>>>>>>>>>>> 
>>>>>>>>>>> (“_meta”, DocID, IsDeleted, RevPosition, RevHash) = [ParentRev,
>>>>>>>> GrandparentRev, …]
>>>>>>>>>>> 
>>>>>>>>>>> The inclusion of IsDeleted, RevPosition and RevHash in the key 
>>>>>>>>>>> should
>>>>>>>> be sufficient (with the right encoding) to create a range query that
>>>>>>>> automatically selects the “winner” according to CouchDB’s arcane rules,
>>>>>>>> which are something like
>>>>>>>>>>> 
>>>>>>>>>>> 1) deleted=false beats deleted=true
>>>>>>>>>>> 2) longer paths (i.e. higher RevPosition) beat shorter ones
>>>>>>>>>>> 3) RevHashes with larger binary values beat ones with smaller values
>>>>>>>>>>> 
>>>>>>>>>>> ===========
>>>>>>>>>>> 
>>>>>>>>>>> OK, that’s all on this topic from me for now. I think this is a
>>>>>>>> particularly exciting area where we start to see the dividends of 
>>>>>>>> splitting
>>>>>>>> up data into multiple KV pairs in FoundationDB :) Cheers,
>>>>>>>>>>> 
>>>>>>>>>>> Adam
>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>>> On Feb 4, 2019, at 2:41 PM, Robert Newson <rnew...@apache.org> 
>>>>>>>>>>>> wrote:
>>>>>>>>>>>> 
>>>>>>>>>>>> This one is quite tightly coupled to the other thread on data 
>>>>>>>>>>>> model,
>>>>>>>> should we start much conversation here before that one gets closer to a
>>>>>>>> solution?
>>>>>>>>>>>> 
>>>>>>>>>>>> --
>>>>>>>>>>>> Robert Samuel Newson
>>>>>>>>>>>> rnew...@apache.org
>>>>>>>>>>>> 
>>>>>>>>>>>> On Mon, 4 Feb 2019, at 19:25, Ilya Khlopotov wrote:
>>>>>>>>>>>>> This is a beginning of a discussion thread about storage of edit
>>>>>>>>>>>>> conflicts and everything which relates to revisions.
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>> 
>>>>>>>> 
>>>>>>>> --
>>>>>>>> Professional Support for Apache CouchDB:
>>>>>>>> https://neighbourhood.ie/couchdb-support/
>>>>>>>> 
>>>>>>>> 
>>>>>>> 
>>>> 
>> 

Reply via email to