summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Kocoloski <kocolosk@apache.org>2010-12-29 03:01:12 +0000
committerAdam Kocoloski <kocolosk@apache.org>2010-12-29 03:01:12 +0000
commit538848259b9d80ccfca5ddb515ebc491f0489c56 (patch)
tree2cfaed8bdd1dea89f03c64082697751d356804ea
parent3c71d543dd863a4b34a779a6b05de1f10b57a3a0 (diff)
Stem revision trees after merging a path, COUCHDB-968
git-svn-id: https://svn.apache.org/repos/asf/couchdb/branches/1.1.x@1053513 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/couchdb/couch_db.erl3
-rw-r--r--src/couchdb/couch_db_updater.erl10
-rw-r--r--src/couchdb/couch_key_tree.erl8
-rwxr-xr-xtest/etap/060-kt-merging.t33
4 files changed, 29 insertions, 25 deletions
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index 4e945ad4..7522a189 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -555,7 +555,8 @@ prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldI
{ok, #full_doc_info{rev_tree=OldTree}} ->
NewRevTree = lists:foldl(
fun(NewDoc, AccTree) ->
- {NewTree, _} = couch_key_tree:merge(AccTree, couch_db:doc_to_tree(NewDoc)),
+ {NewTree, _} = couch_key_tree:merge(AccTree,
+ couch_db:doc_to_tree(NewDoc), Db#db.revs_limit),
NewTree
end,
OldTree, Bucket),
diff --git a/src/couchdb/couch_db_updater.erl b/src/couchdb/couch_db_updater.erl
index 2cce4b69..eb1a3edc 100644
--- a/src/couchdb/couch_db_updater.erl
+++ b/src/couchdb/couch_db_updater.erl
@@ -495,10 +495,11 @@ merge_rev_trees(Limit, MergeConflicts, [NewDocs|RestDocsList],
[OldDocInfo|RestOldInfo], AccNewInfos, AccRemoveSeqs, AccSeq) ->
#full_doc_info{id=Id,rev_tree=OldTree,deleted=OldDeleted,update_seq=OldSeq}
= OldDocInfo,
- NewRevTree0 = lists:foldl(
+ NewRevTree = lists:foldl(
fun({Client, #doc{revs={Pos,[_Rev|PrevRevs]}}=NewDoc}, AccTree) ->
if not MergeConflicts ->
- case couch_key_tree:merge(AccTree, couch_db:doc_to_tree(NewDoc)) of
+ case couch_key_tree:merge(AccTree, couch_db:doc_to_tree(NewDoc),
+ Limit) of
{_NewTree, conflicts} when (not OldDeleted) ->
send_result(Client, Id, {Pos-1,PrevRevs}, conflict),
AccTree;
@@ -529,7 +530,7 @@ merge_rev_trees(Limit, MergeConflicts, [NewDocs|RestDocsList],
NewDoc#doc{revs={OldPos, [OldRev]}}),
NewDoc2 = NewDoc#doc{revs={OldPos + 1, [NewRevId, OldRev]}},
{NewTree2, _} = couch_key_tree:merge(AccTree,
- couch_db:doc_to_tree(NewDoc2)),
+ couch_db:doc_to_tree(NewDoc2), Limit),
% we changed the rev id, this tells the caller we did
send_result(Client, Id, {Pos-1,PrevRevs},
{ok, {OldPos + 1, NewRevId}}),
@@ -543,12 +544,11 @@ merge_rev_trees(Limit, MergeConflicts, [NewDocs|RestDocsList],
end;
true ->
{NewTree, _} = couch_key_tree:merge(AccTree,
- couch_db:doc_to_tree(NewDoc)),
+ couch_db:doc_to_tree(NewDoc), Limit),
NewTree
end
end,
OldTree, NewDocs),
- NewRevTree = couch_key_tree:stem(NewRevTree0, Limit),
if NewRevTree == OldTree ->
% nothing changed
merge_rev_trees(Limit, MergeConflicts, RestDocsList, RestOldInfo,
diff --git a/src/couchdb/couch_key_tree.erl b/src/couchdb/couch_key_tree.erl
index 09712adf..bc723cc2 100644
--- a/src/couchdb/couch_key_tree.erl
+++ b/src/couchdb/couch_key_tree.erl
@@ -12,7 +12,7 @@
-module(couch_key_tree).
--export([merge/2, find_missing/2, get_key_leafs/2, get_full_key_paths/2, get/2]).
+-export([merge/3, find_missing/2, get_key_leafs/2, get_full_key_paths/2, get/2]).
-export([map/2, get_all_leafs/1, count_leafs/1, remove_leafs/2,
get_all_leafs_full/1,stem/2,map_leafs/2]).
@@ -23,6 +23,12 @@
% partial trees arranged by how much they are cut off.
+-spec merge([path()], path(), pos_integer()) -> {[path()],
+ conflicts | no_conflicts}.
+merge(Paths, Path, Depth) ->
+ {Merged, Conflicts} = merge(Paths, Path),
+ {stem(Merged, Depth), Conflicts}.
+
-spec merge([path()], path()) -> {[path()], conflicts | no_conflicts}.
merge(Paths, Path) ->
{ok, Merged, HasConflicts} = merge_one(Paths, Path, [], false),
diff --git a/test/etap/060-kt-merging.t b/test/etap/060-kt-merging.t
index 971e49bf..0e481a52 100755
--- a/test/etap/060-kt-merging.t
+++ b/test/etap/060-kt-merging.t
@@ -15,7 +15,7 @@
main(_) ->
test_util:init_code_path(),
- etap:plan(14),
+ etap:plan(12),
case (catch test()) of
ok ->
etap:end_tests();
@@ -42,77 +42,74 @@ test() ->
etap:is(
{[One], no_conflicts},
- couch_key_tree:merge([], One),
+ couch_key_tree:merge([], One, 10),
"The empty tree is the identity for merge."
),
etap:is(
{TwoSibs, no_conflicts},
- couch_key_tree:merge(TwoSibs, One),
+ couch_key_tree:merge(TwoSibs, One, 10),
"Merging a prefix of a tree with the tree yields the tree."
),
etap:is(
{[One], no_conflicts},
- couch_key_tree:merge([One], One),
+ couch_key_tree:merge([One], One, 10),
"Merging is reflexive."
),
etap:is(
{[TwoChild], no_conflicts},
- couch_key_tree:merge([TwoChild], TwoChild),
+ couch_key_tree:merge([TwoChild], TwoChild, 10),
"Merging two children is still reflexive."
),
etap:is(
{[TwoChildSibs], no_conflicts},
- couch_key_tree:merge([TwoChildSibs], TwoChildSibs),
+ couch_key_tree:merge([TwoChildSibs], TwoChildSibs, 10),
"Merging a tree to itself is itself."),
etap:is(
{[TwoChildSibs], no_conflicts},
- couch_key_tree:merge([TwoChildSibs], Stemmed1b),
+ couch_key_tree:merge([TwoChildSibs], Stemmed1b, 10),
"Merging a tree with a stem."
),
etap:is(
{[TwoChildSibs2], no_conflicts},
- couch_key_tree:merge([TwoChildSibs2], Stemmed1bb),
+ couch_key_tree:merge([TwoChildSibs2], Stemmed1bb, 10),
"Merging a stem at a deeper level."
),
etap:is(
{[TwoChild], no_conflicts},
- couch_key_tree:merge([TwoChild], Stemmed1aa),
+ couch_key_tree:merge([TwoChild], Stemmed1aa, 10),
"Merging a single tree with a deeper stem."
),
etap:is(
{[TwoChild], no_conflicts},
- couch_key_tree:merge([TwoChild], Stemmed1a),
+ couch_key_tree:merge([TwoChild], Stemmed1a, 10),
"Merging a larger stem."
),
etap:is(
{[Stemmed1a], no_conflicts},
- couch_key_tree:merge([Stemmed1a], Stemmed1aa),
+ couch_key_tree:merge([Stemmed1a], Stemmed1aa, 10),
"More merging."
),
Expect1 = [OneChild, Stemmed1aa],
etap:is(
{Expect1, conflicts},
- couch_key_tree:merge([OneChild], Stemmed1aa),
+ couch_key_tree:merge([OneChild], Stemmed1aa, 10),
"Merging should create conflicts."
),
- {MultiPaths, NoConflicts} = couch_key_tree:merge(Expect1, TwoChild),
- etap:is(NoConflicts, no_conflicts, "Merge should have no conflicts."),
- etap:is(length(MultiPaths), 2, "Should have two paths before stemming."),
etap:is(
- couch_key_tree:stem(MultiPaths, 10),
- [TwoChild],
- "Stemming should collapse the paths."
+ {[TwoChild], no_conflicts},
+ couch_key_tree:merge(Expect1, TwoChild, 10),
+ "Merge should have no conflicts."
),
ok.