From 165531bcf223f1c05c4c2eaef7cd2f2943c10584 Mon Sep 17 00:00:00 2001 From: Adam Kocoloski Date: Sat, 15 Aug 2009 05:11:45 +0000 Subject: better failure modes in replication. See COUCHDB-193, COUCHDB-416 If you try to replicate a DB to itself, the replication will proceed, but no checkpoints will be saved, and the logs will say "checkpoint failure: conflict (are you replicating to yourself?)" If you try to specify a non-existent DB as source or target, replication will fail immediately with a 404. The response body will indicate which DB could not be opened. git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@804436 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_rep.erl | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'src/couchdb/couch_rep.erl') diff --git a/src/couchdb/couch_rep.erl b/src/couchdb/couch_rep.erl index c5a07685..cde0a85e 100644 --- a/src/couchdb/couch_rep.erl +++ b/src/couchdb/couch_rep.erl @@ -78,7 +78,11 @@ replicate(PostBody, UserCtx) -> replicate(PostBody, UserCtx) end. -init([RepId, {PostProps}, UserCtx] = InitArgs) -> +init(InitArgs) -> + try do_init(InitArgs) + catch throw:{db_not_found, DbUrl} -> {stop, {db_not_found, DbUrl}} end. + +do_init([RepId, {PostProps}, UserCtx] = InitArgs) -> process_flag(trap_exit, true), SourceProps = proplists:get_value(<<"source">>, PostProps), @@ -177,7 +181,6 @@ handle_info({'EXIT', Pid, Reason}, State) -> {stop, Reason, State}. terminate(normal, State) -> - % ?LOG_DEBUG("replication terminating normally", []), #state{ checkpoint_history = CheckpointHistory, committed_seq = NewSeq, @@ -252,7 +255,9 @@ start_replication_server(Replicator) -> end; {error, {already_started, Pid}} -> ?LOG_DEBUG("replication ~p already running at ~p", [RepId, Pid]), - Pid + Pid; + {error, {{db_not_found, DbUrl}, _}} -> + throw({db_not_found, <<"could not open ", DbUrl/binary>>}) end. compare_replication_logs(SrcDoc, TgtDoc) -> @@ -389,7 +394,7 @@ open_db({Props}, _UserCtx) -> }, case couch_rep_httpc:db_exists(Db) of true -> Db; - false -> throw({db_not_found, Url}) + false -> throw({db_not_found, ?l2b(Url)}) end; open_db(<<"http://",_/binary>>=Url, _) -> open_db({[{<<"url">>,Url}]}, []); @@ -446,17 +451,22 @@ do_checkpoint(State) -> {<<"source_last_seq">>, RecordSeqNum}, {<<"history">>, lists:sublist([NewHistoryEntry | OldHistory], 50)} ]}, - % ?LOG_DEBUG("updating src doc ~p", [SourceLog]), + + try {SrcRevPos,SrcRevId} = update_doc(Source, SourceLog#doc{body=NewRepHistory}, []), - % ?LOG_DEBUG("updating tgt doc ~p", [TargetLog]), {TgtRevPos,TgtRevId} = update_doc(Target, TargetLog#doc{body=NewRepHistory}, []), State#state{ checkpoint_history = NewRepHistory, source_log = SourceLog#doc{revs={SrcRevPos, [SrcRevId]}}, target_log = TargetLog#doc{revs={TgtRevPos, [TgtRevId]}} - }. + } + catch throw:conflict -> + ?LOG_ERROR("checkpoint failure: conflict (are you replicating to yourself?)", + []), + State + end. commit_to_both(Source, Target) -> % commit the src async -- cgit v1.2.3