Permalink
Browse files

backport versioned replication ids, bump couchdb.spec

  • Loading branch information...
tilgovi committed Jun 24, 2010
1 parent 60f4ab8 commit f7b6a7e193fcd0747a590c64c3129fdc37fd4a66
Showing with 155 additions and 1 deletion.
  1. +149 −0 couchdb/couchdb-0.10.2-versioned-replication-ids.patch
  2. +6 −1 rpm/couchdb.spec
@@ -0,0 +1,149 @@
+diff --git a/src/couchdb/couch_rep.erl b/src/couchdb/couch_rep.erl
+index bc80002..b23deee 100644
+--- a/src/couchdb/couch_rep.erl
++++ b/src/couchdb/couch_rep.erl
+@@ -19,6 +19,8 @@
+
+ -include("couch_db.hrl").
+
++-define(REP_ID_VERSION, 2).
++
+ -record(state, {
+ changes_feed,
+ missing_revs,
+@@ -58,7 +60,19 @@ replicate(Source, Target) when is_binary(Source), is_binary(Target) ->
+
+ %% function handling POST to _replicate
+ replicate({Props}=PostBody, UserCtx) ->
+- {BaseId, Extension} = make_replication_id(PostBody, UserCtx),
++ BaseId = make_replication_id({Props}, UserCtx, ?REP_ID_VERSION),
++ Extension = case proplists:get_value(<<"continuous">>, Props, false) of
++ true ->
++ "+continuous";
++ false ->
++ ""
++ end
++ ++ case proplists:get_value(<<"designonly">>, Props, false) of
++ true ->
++ "+designonly";
++ false ->
++ ""
++ end,
+ Replicator = {BaseId ++ Extension,
+ {gen_server, start_link, [?MODULE, [BaseId, PostBody, UserCtx], []]},
+ temporary,
+@@ -108,8 +122,8 @@ do_init([RepId, {PostProps}, UserCtx] = InitArgs) ->
+ Source = open_db(SourceProps, UserCtx),
+ Target = open_db(TargetProps, UserCtx),
+
+- SourceLog = open_replication_log(Source, RepId),
+- TargetLog = open_replication_log(Target, RepId),
++ [SourceLog, TargetLog] = find_replication_logs(
++ [Source, Target], RepId, {PostProps}, UserCtx),
+
+ SourceInfo = dbinfo(Source),
+ TargetInfo = dbinfo(Target),
+@@ -416,26 +430,20 @@ has_session_id(SessionId, [{Props} | Rest]) ->
+ has_session_id(SessionId, Rest)
+ end.
+
+-make_replication_id({Props}, UserCtx) ->
+- %% funky algorithm to preserve backwards compatibility
++% Versioned clauses for generating replication ids
++% If a change is made to how replications are identified
++% add a new clause and increase ?REP_ID_VERSION at the top
++make_replication_id({Props}, UserCtx, 2) ->
+ {ok, HostName} = inet:gethostname(),
+- % Port = mochiweb_socket_server:get(couch_httpd, port),
++ Port = mochiweb_socket_server:get(couch_httpd, port),
+ Src = get_rep_endpoint(UserCtx, proplists:get_value(<<"source">>, Props)),
+- Tgt = get_rep_endpoint(UserCtx, proplists:get_value(<<"target">>, Props)),
+- Base = couch_util:to_hex(erlang:md5(term_to_binary([HostName, Src, Tgt]))),
+- Extension = case proplists:get_value(<<"continuous">>, Props, false) of
+- true ->
+- "+continuous";
+- false ->
+- ""
+- end,
+- Extension2 = case proplists:get_value(<<"designonly">>, Props, false) of
+- true ->
+- "+designonly";
+- false ->
+- ""
+- end,
+- {Base, Extension ++ Extension2}.
++ Tgt = get_rep_endpoint(UserCtx, proplists:get_value(<<"target">>, Props)),
++ couch_util:to_hex(erlang:md5(term_to_binary([HostName, Port, Src, Tgt])));
++make_replication_id({Props}, UserCtx, 1) ->
++ {ok, HostName} = inet:gethostname(),
++ Src = get_rep_endpoint(UserCtx, proplists:get_value(<<"source">>, Props)),
++ Tgt = get_rep_endpoint(UserCtx, proplists:get_value(<<"target">>, Props)),
++ couch_util:to_hex(erlang:md5(term_to_binary([HostName, Src, Tgt]))).
+
+ maybe_add_trailing_slash(Url) ->
+ re:replace(Url, "[^/]$", "&/", [{return, list}]).
+@@ -460,26 +474,52 @@ get_rep_endpoint(_UserCtx, <<"https://",_/binary>>=Url) ->
+ get_rep_endpoint(UserCtx, <<DbName/binary>>) ->
+ {local, DbName, UserCtx}.
+
+-open_replication_log(#http_db{}=Db, RepId) ->
+- DocId = ?LOCAL_DOC_PREFIX ++ RepId,
+- Req = Db#http_db{resource=couch_util:url_encode(DocId)},
++find_replication_logs(Logs, RepId, {Props}, UserCtx) ->
++ LogId = ?l2b(?LOCAL_DOC_PREFIX ++ RepId),
++ fold_replication_logs(Logs, ?REP_ID_VERSION,
++ LogId, LogId, {Props}, UserCtx, []).
++
++% Accumulate the replication logs
++% Falls back to older log document ids and migrates them
++fold_replication_logs([], _Vsn, _LogId, _NewId, {_Props}, _UserCtx, Acc) ->
++ lists:reverse(Acc);
++fold_replication_logs([Db|Rest]=Dbs, Vsn, LogId, NewId,
++ {Props}, UserCtx, Acc) ->
++ case open_replication_log(Db, LogId) of
++ {error, not_found} when Vsn > 1 ->
++ OldRepId = make_replication_id({Props}, UserCtx, Vsn - 1),
++ fold_replication_logs(Dbs, Vsn - 1,
++ ?l2b(?LOCAL_DOC_PREFIX ++ OldRepId), NewId, {Props}, UserCtx, Acc);
++ {error, not_found} ->
++ fold_replication_logs(Rest, ?REP_ID_VERSION, NewId, NewId,
++ {Props}, UserCtx, [#doc{id=NewId}|Acc]);
++ {ok, Doc} when LogId =:= NewId ->
++ fold_replication_logs(Rest, ?REP_ID_VERSION, NewId, NewId,
++ {Props}, UserCtx, [Doc|Acc]);
++ {ok, Doc} ->
++ MigratedLog = #doc{id=NewId,body=Doc#doc.body},
++ fold_replication_logs(Rest, ?REP_ID_VERSION, NewId, NewId,
++ {Props}, UserCtx, [MigratedLog|Acc])
++ end.
++
++open_replication_log(#http_db{}=Db, DocId) ->
++ Req = Db#http_db{resource=couch_util:url_encode(?b2l(DocId))},
+ case couch_rep_httpc:request(Req) of
+ {[{<<"error">>, _}, {<<"reason">>, _}]} ->
+ ?LOG_DEBUG("didn't find a replication log for ~s", [Db#http_db.url]),
+- #doc{id=?l2b(DocId)};
++ {error, not_found};
+ Doc ->
+ ?LOG_DEBUG("found a replication log for ~s", [Db#http_db.url]),
+- couch_doc:from_json_obj(Doc)
++ {ok, couch_doc:from_json_obj(Doc)}
+ end;
+-open_replication_log(Db, RepId) ->
+- DocId = ?l2b(?LOCAL_DOC_PREFIX ++ RepId),
++open_replication_log(Db, DocId) ->
+ case couch_db:open_doc(Db, DocId, []) of
+ {ok, Doc} ->
+ ?LOG_DEBUG("found a replication log for ~s", [Db#db.name]),
+- Doc;
++ {ok, Doc};
+ _ ->
+ ?LOG_DEBUG("didn't find a replication log for ~s", [Db#db.name]),
+- #doc{id=DocId}
++ {error, not_found}
+ end.
+
+ open_db({Props}, _UserCtx) ->
+--
+1.7.0.4
+
View
@@ -3,7 +3,7 @@
%define couchdb_home %{_localstatedir}/lib/couchdb
Name: couchdb
Version: 0.10.2
-Release: 8%{?dist}.lounge3
+Release: 8%{?dist}.lounge4
Summary: A document database server, accessible via a RESTful JSON API
Group: Applications/Databases
@@ -22,6 +22,7 @@ Patch8: %{name}-%{version}-replication-fixes.patch
Patch9: %{name}-%{version}-attbackoff.patch
Patch10: %{name}-%{version}-replicator-settings.patch
Patch11: %{name}-%{version}-sync-logging.patch
+Patch12: %{name}-%{version}-versioned-replication-ids.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: erlang
@@ -65,6 +66,7 @@ JavaScript acting as the default view definition language.
%patch9 -p1 -b .attbackoff
%patch10 -p1 -b .replicator-settings
%patch11 -p1 -b .sync-logging
+%patch12 -p1 -b .versioned-replication-ids
rm -rf src/erlang-oauth
rm -rf src/etap
# Restore original timestamps to avoid reconfiguring
@@ -162,6 +164,9 @@ fi
%dir %attr(0755, %{couchdb_user}, root) %{_localstatedir}/lib/couchdb
%changelog
+* Thu Jun 24 2010 Randall Leeds <randall.leeds@gmail.com> 0.10.2-8-4
+- backport versioned replication id patch, fixes co-hosted couches
+
* Mon Jun 21 2010 Randall Leeds <randall.leeds@gmail.com> 0.10.2-8-3
- `basename $0` to get $prog in init (symlink to run multiple couches)

0 comments on commit f7b6a7e

Please sign in to comment.