Add stats to replication docs When a replication finishes, add its stats to the respective document. These are the same stats as provided by the active tasks API.
COUCHDB-1349 Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/43e83756 Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/43e83756 Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/43e83756 Branch: refs/heads/1.2.x Commit: 43e83756c2dd96012a3d8e19d7e838c4dde1dba2 Parents: df81c2a Author: Filipe David Borba Manana <fdman...@apache.org> Authored: Mon Dec 5 18:30:47 2011 +0000 Committer: Filipe David Borba Manana <fdman...@apache.org> Committed: Mon Dec 5 19:24:29 2011 +0000 ---------------------------------------------------------------------- share/www/script/test/replicator_db.js | 52 ++++++++++++++++++++++++ src/couchdb/couch_doc.erl | 3 + src/couchdb/couch_replication_manager.erl | 15 +++++-- src/couchdb/couch_replicator.erl | 31 +++++++++----- 4 files changed, 85 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb/blob/43e83756/share/www/script/test/replicator_db.js ---------------------------------------------------------------------- diff --git a/share/www/script/test/replicator_db.js b/share/www/script/test/replicator_db.js index 46d3873..a51cce8 100644 --- a/share/www/script/test/replicator_db.js +++ b/share/www/script/test/replicator_db.js @@ -123,6 +123,17 @@ couchTests.replicator_db = function(debug) { T(repDoc1._replication_state === "completed", "simple"); T(typeof repDoc1._replication_state_time === "string"); T(typeof repDoc1._replication_id === "string"); + T(typeof repDoc1._replication_stats === "object", "doc has stats"); + var stats = repDoc1._replication_stats; + TEquals(docs1.length, stats.revisions_checked, + "right # of revisions_checked"); + TEquals(docs1.length, stats.missing_revisions_found, + "right # of missing_revisions_found"); + TEquals(docs1.length, stats.docs_read, "right # of docs_read"); + TEquals(docs1.length, stats.docs_written, "right # of docs_written"); + TEquals(0, stats.doc_write_failures, "right # of doc_write_failures"); + TEquals(dbA.info().update_seq, stats.checkpointed_source_seq, + "right checkpointed_source_seq"); } @@ -175,6 +186,15 @@ couchTests.replicator_db = function(debug) { T(repDoc1._replication_state === "completed", "filtered"); T(typeof repDoc1._replication_state_time === "string"); T(typeof repDoc1._replication_id === "string"); + T(typeof repDoc1._replication_stats === "object", "doc has stats"); + var stats = repDoc1._replication_stats; + TEquals(2, stats.revisions_checked, "right # of revisions_checked"); + TEquals(2, stats.missing_revisions_found, "right # of missing_revisions_found"); + TEquals(2, stats.docs_read, "right # of docs_read"); + TEquals(1, stats.docs_written, "right # of docs_written"); + TEquals(1, stats.doc_write_failures, "right # of doc_write_failures"); + TEquals(dbA.info().update_seq, stats.checkpointed_source_seq, + "right checkpointed_source_seq"); } @@ -305,6 +325,17 @@ couchTests.replicator_db = function(debug) { copy = dbB.open("_design/mydesign"); T(copy === null); + + repDoc = repDb.open(repDoc._id); + T(typeof repDoc._replication_stats === "object", "doc has stats"); + var stats = repDoc._replication_stats; + TEquals(3, stats.revisions_checked, "right # of revisions_checked"); + TEquals(3, stats.missing_revisions_found, "right # of missing_revisions_found"); + TEquals(3, stats.docs_read, "right # of docs_read"); + TEquals(2, stats.docs_written, "right # of docs_written"); + TEquals(1, stats.doc_write_failures, "right # of doc_write_failures"); + TEquals(dbA.info().update_seq, stats.checkpointed_source_seq, + "right checkpointed_source_seq"); } @@ -334,6 +365,17 @@ couchTests.replicator_db = function(debug) { T(repDoc1_copy._replication_state === "completed"); T(typeof repDoc1_copy._replication_state_time === "string"); T(typeof repDoc1_copy._replication_id === "string"); + T(typeof repDoc1_copy._replication_stats === "object", "doc has stats"); + var stats = repDoc1_copy._replication_stats; + TEquals(docs1.length, stats.revisions_checked, + "right # of revisions_checked"); + TEquals(docs1.length, stats.missing_revisions_found, + "right # of missing_revisions_found"); + TEquals(docs1.length, stats.docs_read, "right # of docs_read"); + TEquals(docs1.length, stats.docs_written, "right # of docs_written"); + TEquals(0, stats.doc_write_failures, "right # of doc_write_failures"); + TEquals(dbA.info().update_seq, stats.checkpointed_source_seq, + "right checkpointed_source_seq"); var newDoc = { _id: "doc666", @@ -366,6 +408,16 @@ couchTests.replicator_db = function(debug) { T(typeof repDoc2_copy._replication_state_time === "string"); T(typeof repDoc2_copy._replication_id === "string"); T(repDoc2_copy._replication_id === repDoc1_copy._replication_id); + T(typeof repDoc2_copy._replication_stats === "object", "doc has stats"); + stats = repDoc2_copy._replication_stats; + TEquals(1, stats.revisions_checked, "right # of revisions_checked"); + TEquals(1, stats.missing_revisions_found, + "right # of missing_revisions_found"); + TEquals(1, stats.docs_read, "right # of docs_read"); + TEquals(1, stats.docs_written, "right # of docs_written"); + TEquals(0, stats.doc_write_failures, "right # of doc_write_failures"); + TEquals(dbA.info().update_seq, stats.checkpointed_source_seq, + "right checkpointed_source_seq"); } http://git-wip-us.apache.org/repos/asf/couchdb/blob/43e83756/src/couchdb/couch_doc.erl ---------------------------------------------------------------------- diff --git a/src/couchdb/couch_doc.erl b/src/couchdb/couch_doc.erl index 7199d07..b7c2a17 100644 --- a/src/couchdb/couch_doc.erl +++ b/src/couchdb/couch_doc.erl @@ -296,6 +296,9 @@ transfer_fields([{<<"_replication_state_time">>, _} = Field | Rest], transfer_fields([{<<"_replication_id">>, _} = Field | Rest], #doc{body=Fields} = Doc) -> transfer_fields(Rest, Doc#doc{body=[Field|Fields]}); +transfer_fields([{<<"_replication_stats">>, _} = Field | Rest], + #doc{body=Fields} = Doc) -> + transfer_fields(Rest, Doc#doc{body=[Field|Fields]}); % unknown special field transfer_fields([{<<"_",Name/binary>>, _} | _], _) -> http://git-wip-us.apache.org/repos/asf/couchdb/blob/43e83756/src/couchdb/couch_replication_manager.erl ---------------------------------------------------------------------- diff --git a/src/couchdb/couch_replication_manager.erl b/src/couchdb/couch_replication_manager.erl index 801af7c..81c6d07 100644 --- a/src/couchdb/couch_replication_manager.erl +++ b/src/couchdb/couch_replication_manager.erl @@ -14,7 +14,7 @@ -behaviour(gen_server). % public API --export([replication_started/1, replication_completed/1, replication_error/2]). +-export([replication_started/1, replication_completed/2, replication_error/2]). % gen_server callbacks -export([start_link/0, init/1, handle_call/3, handle_info/2, handle_cast/2]). @@ -63,19 +63,22 @@ replication_started(#rep{id = {BaseId, _} = RepId}) -> #rep_state{rep = #rep{doc_id = DocId}} -> update_rep_doc(DocId, [ {<<"_replication_state">>, <<"triggered">>}, - {<<"_replication_id">>, ?l2b(BaseId)}]), + {<<"_replication_id">>, ?l2b(BaseId)}, + {<<"_replication_stats">>, undefined}]), ok = gen_server:call(?MODULE, {rep_started, RepId}, infinity), ?LOG_INFO("Document `~s` triggered replication `~s`", [DocId, pp_rep_id(RepId)]) end. -replication_completed(#rep{id = RepId}) -> +replication_completed(#rep{id = RepId}, Stats) -> case rep_state(RepId) of nil -> ok; #rep_state{rep = #rep{doc_id = DocId}} -> - update_rep_doc(DocId, [{<<"_replication_state">>, <<"completed">>}]), + update_rep_doc(DocId, [ + {<<"_replication_state">>, <<"completed">>}, + {<<"_replication_stats">>, {Stats}}]), ok = gen_server:call(?MODULE, {rep_complete, RepId}, infinity), ?LOG_INFO("Replication `~s` finished (triggered by document `~s`)", [pp_rep_id(RepId), DocId]) @@ -516,7 +519,9 @@ update_rep_doc(RepDocId, KVs) -> update_rep_doc(RepDb, #doc{body = {RepDocBody}} = RepDoc, KVs) -> NewRepDocBody = lists:foldl( - fun({<<"_replication_state">> = K, State} = KV, Body) -> + fun({K, undefined}, Body) -> + lists:keydelete(K, 1, Body); + ({<<"_replication_state">> = K, State} = KV, Body) -> case get_value(K, Body) of State -> Body; http://git-wip-us.apache.org/repos/asf/couchdb/blob/43e83756/src/couchdb/couch_replicator.erl ---------------------------------------------------------------------- diff --git a/src/couchdb/couch_replicator.erl b/src/couchdb/couch_replicator.erl index 40cb9a4..db7fe89 100644 --- a/src/couchdb/couch_replicator.erl +++ b/src/couchdb/couch_replicator.erl @@ -459,7 +459,7 @@ terminate(normal, #rep_state{rep_details = #rep{id = RepId} = Rep, checkpoint_history = CheckpointHistory} = State) -> terminate_cleanup(State), couch_replication_notifier:notify({finished, RepId, CheckpointHistory}), - couch_replication_manager:replication_completed(Rep); + couch_replication_manager:replication_completed(Rep, rep_stats(State)); terminate(shutdown, #rep_state{rep_details = #rep{id = RepId}} = State) -> % cancelled replication throught ?MODULE:cancel_replication/1 @@ -916,18 +916,11 @@ source_cur_seq(#rep_state{source = Db, source_seq = Seq}) -> update_task(State) -> #rep_state{ current_through_seq = {_, CurSeq}, - committed_seq = {_, CommittedSeq}, - source_seq = SourceCurSeq, - stats = Stats + source_seq = SourceCurSeq } = State, - couch_task_status:update([ - {revisions_checked, Stats#rep_stats.missing_checked}, - {missing_revisions_found, Stats#rep_stats.missing_found}, - {docs_read, Stats#rep_stats.docs_read}, - {docs_written, Stats#rep_stats.docs_written}, - {doc_write_failures, Stats#rep_stats.doc_write_failures}, + couch_task_status:update( + rep_stats(State) ++ [ {source_seq, SourceCurSeq}, - {checkpointed_source_seq, CommittedSeq}, case is_number(CurSeq) andalso is_number(SourceCurSeq) of true -> case SourceCurSeq of @@ -940,3 +933,19 @@ update_task(State) -> {progress, null} end ]). + + +rep_stats(State) -> + #rep_state{ + committed_seq = {_, CommittedSeq}, + stats = Stats + } = State, + [ + {revisions_checked, Stats#rep_stats.missing_checked}, + {missing_revisions_found, Stats#rep_stats.missing_found}, + {docs_read, Stats#rep_stats.docs_read}, + {docs_written, Stats#rep_stats.docs_written}, + {doc_write_failures, Stats#rep_stats.doc_write_failures}, + {checkpointed_source_seq, CommittedSeq} + ]. +