Return-Path: Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: (qmail 68549 invoked from network); 28 Sep 2010 16:50:24 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 28 Sep 2010 16:50:24 -0000 Received: (qmail 17379 invoked by uid 500); 28 Sep 2010 16:50:24 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 17312 invoked by uid 500); 28 Sep 2010 16:50:23 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 17305 invoked by uid 99); 28 Sep 2010 16:50:23 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 28 Sep 2010 16:50:23 +0000 X-ASF-Spam-Status: No, hits=-1996.4 required=10.0 tests=ALL_TRUSTED,FS_REPLICA X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 28 Sep 2010 16:50:20 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id DFCAE23889BF; Tue, 28 Sep 2010 16:49:58 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1002259 - in /couchdb/trunk: share/www/script/test/replication.js src/couchdb/couch_rep.erl Date: Tue, 28 Sep 2010 16:49:58 -0000 To: commits@couchdb.apache.org From: fdmanana@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100928164958.DFCAE23889BF@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fdmanana Date: Tue Sep 28 16:49:58 2010 New Revision: 1002259 URL: http://svn.apache.org/viewvc?rev=1002259&view=rev Log: Replicator fix: for a filtered replication, the replication ID should take into account the filter function's code and not only its name. Closes COUCHDB-892. Modified: couchdb/trunk/share/www/script/test/replication.js couchdb/trunk/src/couchdb/couch_rep.erl Modified: couchdb/trunk/share/www/script/test/replication.js URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/replication.js?rev=1002259&r1=1002258&r2=1002259&view=diff ============================================================================== --- couchdb/trunk/share/www/script/test/replication.js (original) +++ couchdb/trunk/share/www/script/test/replication.js Tue Sep 28 16:49:58 2010 @@ -452,31 +452,17 @@ couchTests.replication = function(debug) } // test filtered replication - - var sourceDb = new CouchDB( - "test_suite_filtered_rep_db_a", {"X-Couch-Full-Commit":"false"} - ); - - sourceDb.deleteDb(); - sourceDb.createDb(); - - T(sourceDb.save({_id:"foo1",value:1}).ok); - T(sourceDb.save({_id:"foo2",value:2}).ok); - T(sourceDb.save({_id:"foo3",value:3}).ok); - T(sourceDb.save({_id:"foo4",value:4}).ok); - T(sourceDb.save({ - "_id": "_design/mydesign", - "language" : "javascript", - "filters" : { - "myfilter" : (function(doc, req) { - if (doc.value < Number(req.query.maxvalue)) { - return true; - } else { - return false; - } - }).toString() + var filterFun1 = (function(doc, req) { + if (doc.value < Number(req.query.maxvalue)) { + return true; + } else { + return false; } - }).ok); + }).toString(); + + var filterFun2 = (function(doc, req) { + return true; + }).toString(); var dbPairs = [ {source:"test_suite_filtered_rep_db_a", @@ -488,9 +474,28 @@ couchTests.replication = function(debug) {source:CouchDB.protocol + host + "/test_suite_filtered_rep_db_a", target:CouchDB.protocol + host + "/test_suite_filtered_rep_db_b"} ]; + var sourceDb = new CouchDB("test_suite_filtered_rep_db_a"); + var targetDb = new CouchDB("test_suite_filtered_rep_db_b"); for (var i = 0; i < dbPairs.length; i++) { - var targetDb = new CouchDB("test_suite_filtered_rep_db_b"); + sourceDb.deleteDb(); + sourceDb.createDb(); + + T(sourceDb.save({_id: "foo1", value: 1}).ok); + T(sourceDb.save({_id: "foo2", value: 2}).ok); + T(sourceDb.save({_id: "foo3", value: 3}).ok); + T(sourceDb.save({_id: "foo4", value: 4}).ok); + + var ddoc = { + "_id": "_design/mydesign", + "language": "javascript", + "filters": { + "myfilter": filterFun1 + } + }; + + T(sourceDb.save(ddoc).ok); + targetDb.deleteDb(); targetDb.createDb(); @@ -526,6 +531,45 @@ couchTests.replication = function(debug) var docFoo4 = targetDb.open("foo4"); T(docFoo4 === null); + + // replication should start from scratch after the filter's code changed + + ddoc.filters.myfilter = filterFun2; + T(sourceDb.save(ddoc).ok); + + repResult = CouchDB.replicate(dbA, dbB, { + body: { + "filter" : "mydesign/myfilter", + "query_params" : { + "maxvalue": "3" + } + } + }); + + T(repResult.ok); + T(repResult.history instanceof Array); + T(repResult.history.length === 1); + T(repResult.history[0].docs_written === 3); + T(repResult.history[0].docs_read === 3); + T(repResult.history[0].doc_write_failures === 0); + + docFoo1 = targetDb.open("foo1"); + T(docFoo1 !== null); + T(docFoo1.value === 1); + + docFoo2 = targetDb.open("foo2"); + T(docFoo2 !== null); + T(docFoo2.value === 2); + + docFoo3 = targetDb.open("foo3"); + T(docFoo3 !== null); + T(docFoo3.value === 3); + + docFoo4 = targetDb.open("foo4"); + T(docFoo4 !== null); + T(docFoo4.value === 4); + + T(targetDb.open("_design/mydesign") !== null); } }; Modified: couchdb/trunk/src/couchdb/couch_rep.erl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_rep.erl?rev=1002259&r1=1002258&r2=1002259&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_rep.erl (original) +++ couchdb/trunk/src/couchdb/couch_rep.erl Tue Sep 28 16:49:58 2010 @@ -486,14 +486,14 @@ make_replication_id({Props}, UserCtx, 2) Port = mochiweb_socket_server:get(couch_httpd, port), Src = get_rep_endpoint(UserCtx, ?getv(<<"source">>, Props)), Tgt = get_rep_endpoint(UserCtx, ?getv(<<"target">>, Props)), - maybe_append_filters({Props}, [HostName, Port, Src, Tgt]); + maybe_append_filters({Props}, [HostName, Port, Src, Tgt], UserCtx); make_replication_id({Props}, UserCtx, 1) -> {ok, HostName} = inet:gethostname(), Src = get_rep_endpoint(UserCtx, ?getv(<<"source">>, Props)), Tgt = get_rep_endpoint(UserCtx, ?getv(<<"target">>, Props)), - maybe_append_filters({Props}, [HostName, Src, Tgt]). + maybe_append_filters({Props}, [HostName, Src, Tgt], UserCtx). -maybe_append_filters({Props}, Base) -> +maybe_append_filters({Props}, Base, UserCtx) -> Base2 = Base ++ case ?getv(<<"filter">>, Props) of undefined -> @@ -504,10 +504,20 @@ maybe_append_filters({Props}, Base) -> [DocIds] end; Filter -> - [Filter, ?getv(<<"query_params">>, Props, {[]})] + [filter_code(Filter, Props, UserCtx), + ?getv(<<"query_params">>, Props, {[]})] end, couch_util:to_hex(couch_util:md5(term_to_binary(Base2))). +filter_code(Filter, Props, UserCtx) -> + {match, [DDocName, FilterName]} = + re:run(Filter, "(.*?)/(.*)", [{capture, [1, 2], binary}]), + ProxyParams = parse_proxy_params(?getv(<<"proxy">>, Props, [])), + Source = open_db(?getv(<<"source">>, Props), UserCtx, ProxyParams), + {ok, #doc{body = Body}} = open_doc(Source, <<"_design/", DDocName/binary>>), + Code = couch_util:get_nested_json_value(Body, [<<"filters">>, FilterName]), + re:replace(Code, "^\s*(.*?)\s*$", "\\1", [{return, binary}]). + maybe_add_trailing_slash(Url) -> re:replace(Url, "[^/]$", "&/", [{return, list}]). @@ -556,26 +566,27 @@ fold_replication_logs([Db|Rest]=Dbs, Vsn RepProps, UserCtx, [MigratedLog|Acc]) end. -open_replication_log(#http_db{}=Db, DocId) -> - Req = Db#http_db{resource=couch_util:encode_doc_id(DocId)}, - case couch_rep_httpc:request(Req) of - {[{<<"error">>, _}, {<<"reason">>, _}]} -> - ?LOG_DEBUG("didn't find a replication log for ~s", [Db#http_db.url]), - {error, not_found}; - Doc -> - ?LOG_DEBUG("found a replication log for ~s", [Db#http_db.url]), - {ok, couch_doc:from_json_obj(Doc)} - end; open_replication_log(Db, DocId) -> - case couch_db:open_doc(Db, DocId, []) of + case open_doc(Db, DocId) of {ok, Doc} -> - ?LOG_DEBUG("found a replication log for ~s", [Db#db.name]), + ?LOG_DEBUG("found a replication log for ~s", [dbname(Db)]), {ok, Doc}; _ -> - ?LOG_DEBUG("didn't find a replication log for ~s", [Db#db.name]), + ?LOG_DEBUG("didn't find a replication log for ~s", [dbname(Db)]), {error, not_found} end. +open_doc(#http_db{} = Db, DocId) -> + Req = Db#http_db{resource = couch_util:encode_doc_id(DocId)}, + case couch_rep_httpc:request(Req) of + {[{<<"error">>, _}, {<<"reason">>, _}]} -> + {error, not_found}; + Doc -> + {ok, couch_doc:from_json_obj(Doc)} + end; +open_doc(Db, DocId) -> + couch_db:open_doc(Db, DocId). + open_db(Props, UserCtx, ProxyParams) -> open_db(Props, UserCtx, ProxyParams, false).