Created
August 31, 2010 21:03
-
-
Save tilgovi/559749 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/couchdb/couch_db_updater.erl b/src/couchdb/couch_db_updater.erl | |
index 19a4c16..6099d0a 100644 | |
--- a/src/couchdb/couch_db_updater.erl | |
+++ b/src/couchdb/couch_db_updater.erl | |
@@ -439,15 +439,42 @@ refresh_validate_doc_funs(Db) -> | |
% rev tree functions | |
-flush_trees(_Db, [], AccFlushedTrees) -> | |
- {ok, lists:reverse(AccFlushedTrees)}; | |
-flush_trees(#db{fd=Fd,header=Header}=Db, | |
- [InfoUnflushed | RestUnflushed], AccFlushed) -> | |
- #full_doc_info{update_seq=UpdateSeq, rev_tree=Unflushed} = InfoUnflushed, | |
- Flushed = couch_key_tree:map( | |
- fun(_Rev, Value) -> | |
+flush_trees(_Db, [], AccDocInfo, []) -> | |
+ {ok, lists:reverse(AccDocInfo)}; | |
+flush_trees(#db{fd=Fd,header=Header}, [], AccDocInfo, AccUnflushed) -> | |
+ {ok, NewSummaryPointers} = | |
+ case Header#db_header.disk_version < 4 of | |
+ true -> | |
+ couch_file:append_terms(Fd, AccUnflushed); | |
+ false -> | |
+ couch_file:append_terms_md5(Fd, AccUnflushed) | |
+ end, | |
+ {Flushed, []} = | |
+ lists:foldl( | |
+ fun(#full_doc_info{update_seq=UpdateSeq, rev_tree=RevTree}=DocInfo, | |
+ {FlushedInfoAcc, UnusedSummaryPointers}) -> | |
+ {FlushedRevTree, UnusedSummaryPointers2} = | |
+ couch_key_tree:mapfoldl( | |
+ fun(_Rev, Value, SummaryPointers) -> | |
+ case Value of | |
+ #doc{deleted=IsDeleted} -> | |
+ [NewSummaryPointer|Rest] = SummaryPointers, | |
+ {{IsDeleted, NewSummaryPointer, UpdateSeq}, Rest}; | |
+ _ -> | |
+ {Value, SummaryPointers} | |
+ end | |
+ end, UnusedSummaryPointers, RevTree), | |
+ {[DocInfo#full_doc_info{rev_tree=FlushedRevTree}|FlushedInfoAcc], | |
+ UnusedSummaryPointers2} | |
+ end, {[], NewSummaryPointers}, AccDocInfo), | |
+ {ok, Flushed}; | |
+flush_trees(#db{fd=Fd}=Db, [InfoUnflushed | RestUnflushed], | |
+ AccDocInfo, AccUnflushed) -> | |
+ #full_doc_info{rev_tree=RevTree} = InfoUnflushed, | |
+ AccUnflushed2 = couch_key_tree:foldl( | |
+ fun(_Rev, Value, Acc) -> | |
case Value of | |
- #doc{atts=Atts,deleted=IsDeleted}=Doc -> | |
+ #doc{atts=Atts}=Doc -> | |
% this node value is actually an unwritten document summary, | |
% write to disk. | |
% make sure the Fd in the written bins is the same Fd we are | |
@@ -468,20 +495,13 @@ flush_trees(#db{fd=Fd,header=Header}=Db, | |
" changed. Possibly retrying.", []), | |
throw(retry) | |
end, | |
- {ok, NewSummaryPointer} = | |
- case Header#db_header.disk_version < 4 of | |
- true -> | |
- couch_file:append_term(Fd, {Doc#doc.body, DiskAtts}); | |
- false -> | |
- couch_file:append_term_md5(Fd, {Doc#doc.body, DiskAtts}) | |
- end, | |
- {IsDeleted, NewSummaryPointer, UpdateSeq}; | |
+ UnflushedBody = {Doc#doc.body, DiskAtts}, | |
+ [UnflushedBody|Acc]; | |
_ -> | |
- Value | |
+ Acc | |
end | |
- end, Unflushed), | |
- flush_trees(Db, RestUnflushed, [InfoUnflushed#full_doc_info{rev_tree=Flushed} | AccFlushed]). | |
- | |
+ end, AccUnflushed, RevTree), | |
+ flush_trees(Db, RestUnflushed, [InfoUnflushed | AccDocInfo], AccUnflushed2). | |
send_result(Client, Id, OriginalRevs, NewResult) -> | |
% used to send a result to the client | |
@@ -605,7 +625,7 @@ update_docs_int(Db, DocsList, NonRepDocs, MergeConflicts, FullCommit) -> | |
% Write out the document summaries (the bodies are stored in the nodes of | |
% the trees, the attachments are already written to disk) | |
- {ok, FlushedFullDocInfos} = flush_trees(Db2, NewFullDocInfos, []), | |
+ {ok, FlushedFullDocInfos} = flush_trees(Db2, NewFullDocInfos, [], []), | |
{IndexFullDocInfos, IndexDocInfos} = | |
new_index_entries(FlushedFullDocInfos, [], []), | |
diff --git a/src/couchdb/couch_file.erl b/src/couchdb/couch_file.erl | |
index 0a89171..f5e7530 100644 | |
--- a/src/couchdb/couch_file.erl | |
+++ b/src/couchdb/couch_file.erl | |
@@ -27,6 +27,8 @@ | |
-export([append_term/2, pread_term/2, pread_iolist/2, write_header/2]). | |
-export([pread_binary/2, read_header/1, truncate/2, upgrade_old_header/2]). | |
-export([append_term_md5/2,append_binary_md5/2]). | |
+-export([append_terms/2, append_terms_md5/2]). | |
+-export([append_binaries/2, append_binaries_md5/2]). | |
-export([init/1, terminate/2, handle_call/3, handle_cast/2, code_change/3, handle_info/2]). | |
-export([delete/2,delete/3,init_delete_dir/1]). | |
@@ -74,6 +76,11 @@ append_term(Fd, Term) -> | |
append_term_md5(Fd, Term) -> | |
append_binary_md5(Fd, term_to_binary(Term)). | |
+append_terms(Fd, Terms) -> | |
+ append_terms(Fd, lists:map(fun term_to_binary/1, Terms)). | |
+ | |
+append_terms_md5(Fd, Terms) -> | |
+ append_binaries_md5(Fd, lists:map(fun term_to_binary/1, Terms)). | |
%%---------------------------------------------------------------------- | |
%% Purpose: To append an Erlang binary to the end of the file. | |
@@ -93,6 +100,22 @@ append_binary_md5(Fd, Bin) -> | |
gen_server:call(Fd, {append_bin, | |
[<<1:1/integer,Size:31/integer>>, couch_util:md5(Bin), Bin]}, infinity). | |
+append_binaries(Fd, Bins) -> | |
+ gen_server:call(Fd, {append_bins, | |
+ lists:map( | |
+ fun(Bin) -> | |
+ Size = iolist_size(Bin), | |
+ [<<0:1/integer,Size:31/integer>>, Bin] | |
+ end, Bins)}, infinity). | |
+ | |
+append_binaries_md5(Fd, Bins) -> | |
+ gen_server:call(Fd, {append_bins, | |
+ lists:map( | |
+ fun(Bin) -> | |
+ Size = iolist_size(Bin), | |
+ [<<1:1/integer,Size:31/integer>>, couch_util:md5(Bin), Bin] | |
+ end, Bins)}, infinity). | |
+ | |
%%---------------------------------------------------------------------- | |
%% Purpose: Reads a term from a file that was written with append_term | |
@@ -331,6 +354,19 @@ handle_call({append_bin, Bin}, _From, #file{fd=Fd, eof=Pos}=File) -> | |
Error -> | |
{reply, Error, File} | |
end; | |
+handle_call({append_bins, Bins}, _From, #file{fd=Fd, eof=Pos}=File) -> | |
+ {BlockPosList, NewPos} = lists:mapfoldl( | |
+ fun(Bin, OutPos) -> | |
+ Blocks = make_blocks(OutPos rem ?SIZE_BLOCK, Bin), | |
+ {{Blocks, OutPos}, OutPos+iolist_size(Blocks)} | |
+ end, Pos, Bins), | |
+ {BlockList, PosList} = lists:unzip(BlockPosList), | |
+ case file:write(Fd, BlockList) of | |
+ ok -> | |
+ {reply, {ok, PosList}, File#file{eof=NewPos}}; | |
+ Error -> | |
+ {reply, Error, File} | |
+ end; | |
handle_call({write_header, Bin}, _From, #file{fd=Fd, eof=Pos}=File) -> | |
BinSize = size(Bin), | |
case Pos rem ?SIZE_BLOCK of | |
diff --git a/src/couchdb/couch_key_tree.erl b/src/couchdb/couch_key_tree.erl | |
index 4fe09bf..ad4d092 100644 | |
--- a/src/couchdb/couch_key_tree.erl | |
+++ b/src/couchdb/couch_key_tree.erl | |
@@ -13,7 +13,7 @@ | |
-module(couch_key_tree). | |
-export([merge/2, 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, | |
+-export([map/2, foldl/3, mapfoldl/3, get_all_leafs/1, count_leafs/1, remove_leafs/2, | |
get_all_leafs_full/1,stem/2,map_leafs/2]). | |
% a key tree looks like this: | |
@@ -294,6 +294,33 @@ map_simple(Fun, Pos, [{Key, Value, SubTree} | RestTree]) -> | |
if SubTree == [] -> leaf; true -> branch end), | |
[{Key, Value2, map_simple(Fun, Pos + 1, SubTree)} | map_simple(Fun, Pos, RestTree)]. | |
+foldl(_Fun, Acc, []) -> | |
+ Acc; | |
+foldl(Fun, Acc, [{Pos, Tree}|Rest]) -> | |
+ Acc2 = foldl_simple(Fun, Acc, Pos, [Tree]), | |
+ foldl(Fun, Acc2, Rest). | |
+ | |
+foldl_simple(_Fun, Acc, _Pos, []) -> | |
+ Acc; | |
+foldl_simple(Fun, Acc, Pos, [{Key, Value, SubTree} | RestTree]) -> | |
+ Acc2 = Fun({Pos, Key}, Value, Acc), | |
+ Acc3 = foldl_simple(Fun, Acc2, Pos + 1, SubTree), | |
+ foldl_simple(Fun, Acc3, Pos, RestTree). | |
+ | |
+mapfoldl(_Fun, Acc, []) -> | |
+ {[], Acc}; | |
+mapfoldl(Fun, Acc, [{Pos, Tree}|Rest]) -> | |
+ {[NewTree], Acc2} = mapfoldl_simple(Fun, Acc, Pos, [Tree]), | |
+ {NewRest, Acc3} = mapfoldl(Fun, Acc2, Rest), | |
+ {[{Pos, NewTree} | NewRest], Acc3}. | |
+ | |
+mapfoldl_simple(_Fun, Acc, _Pos, []) -> | |
+ {[], Acc}; | |
+mapfoldl_simple(Fun, Acc, Pos, [{Key, Value, Subtree} | RestTree ]) -> | |
+ {Value2, Acc2} = Fun({Pos, Key}, Value, Acc), | |
+ {NewSubTree, Acc3} = mapfoldl_simple(Fun, Acc2, Pos, Subtree), | |
+ {NewRestTree, Acc4} = mapfoldl_simple(Fun, Acc3, Pos, RestTree), | |
+ {[{Key, Value2, NewSubTree} | NewRestTree], Acc4}. | |
map_leafs(_Fun, []) -> | |
[]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment