Return-Path: Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: (qmail 82557 invoked from network); 1 Aug 2009 13:51:00 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 1 Aug 2009 13:51:00 -0000 Received: (qmail 96903 invoked by uid 500); 1 Aug 2009 13:51:04 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 96829 invoked by uid 500); 1 Aug 2009 13:51:04 -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 96820 invoked by uid 99); 1 Aug 2009 13:51:04 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 01 Aug 2009 13:51:04 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED 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; Sat, 01 Aug 2009 13:51:00 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 55A9523888DD; Sat, 1 Aug 2009 13:50:39 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r799862 - in /couchdb/trunk: share/www/script/test/changes.js src/couchdb/couch_httpd_db.erl Date: Sat, 01 Aug 2009 13:50:39 -0000 To: commits@couchdb.apache.org From: jan@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090801135039.55A9523888DD@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: jan Date: Sat Aug 1 13:50:38 2009 New Revision: 799862 URL: http://svn.apache.org/viewvc?rev=799862&view=rev Log: implement longpolling for _changes, unify _changes-mode parameters, patch by Benoit Chesneau, closes COUCHDB-241 Modified: couchdb/trunk/share/www/script/test/changes.js couchdb/trunk/src/couchdb/couch_httpd_db.erl Modified: couchdb/trunk/share/www/script/test/changes.js URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/changes.js?rev=799862&r1=799861&r2=799862&view=diff ============================================================================== --- couchdb/trunk/share/www/script/test/changes.js (original) +++ couchdb/trunk/share/www/script/test/changes.js Sat Aug 1 13:50:38 2009 @@ -44,7 +44,7 @@ T(jsonp_flag == 1); - req = CouchDB.request("GET", "/test_suite_db/_changes?continuous=true&timeout=10"); + req = CouchDB.request("GET", "/test_suite_db/_changes?feed=continuous&timeout=10"); var resp = JSON.parse(req.responseText); T(resp.results.length == 1 && resp.last_seq==1) T(resp.results[0].changes[0].rev == docFoo._rev) @@ -75,7 +75,7 @@ } - xhr.open("GET", "/test_suite_db/_changes?continuous=true", true); + xhr.open("GET", "/test_suite_db/_changes?feed=continuous", true); xhr.send(""); var docBar = {_id:"bar", bar:1}; @@ -113,7 +113,7 @@ xhr = CouchDB.newXhr(); //verify the hearbeat newlines are sent - xhr.open("GET", "/test_suite_db/_changes?continuous=true&heartbeat=10", true); + xhr.open("GET", "/test_suite_db/_changes?feed=continuous&heartbeat=10", true); xhr.send(""); sleep(100); @@ -122,6 +122,39 @@ T(str.charAt(str.length - 1) == "\n") T(str.charAt(str.length - 2) == "\n") + + + // test longpolling + xhr = CouchDB.newXhr(); + + xhr.open("GET", "/test_suite_db/_changes?feed=longpoll", true); + xhr.send(""); + + sleep(100); + var lines = xhr.responseText.split("\n"); + T(lines[5]=='"last_seq":3}'); + + xhr = CouchDB.newXhr(); + + xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&since=3", true); + xhr.send(""); + + sleep(100); + + var docBarz = {_id:"barz", bar:1}; + db.save(docBarz); + + sleep(100); + + var lines = xhr.responseText.split("\n"); + + change = parse_changes_line(lines[1]); + + T(change.seq == 4); + T(change.id == "barz"); + T(change.changes[0].rev == docBarz._rev); + T(lines[3]=='"last_seq":4}'); + } // test the filtered changes Modified: couchdb/trunk/src/couchdb/couch_httpd_db.erl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_db.erl?rev=799862&r1=799861&r2=799862&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_httpd_db.erl (original) +++ couchdb/trunk/src/couchdb/couch_httpd_db.erl Sat Aug 1 13:50:38 2009 @@ -64,12 +64,13 @@ fun() -> send_chunk(Resp, "\n"), ok end} end. + handle_changes_req(#httpd{method='GET',path_parts=[DbName|_]}=Req, Db) -> StartSeq = list_to_integer(couch_httpd:qs_value(Req, "since", "0")), {ok, Resp} = start_json_response(Req, 200), send_chunk(Resp, "{\"results\":[\n"), - case couch_httpd:qs_value(Req, "continuous", "false") of - "true" -> + case couch_httpd:qs_value(Req, "feed", "normal") of + ResponseType when ResponseType == "continuous" orelse ResponseType == "longpoll"-> Self = self(), {ok, Notify} = couch_db_update_notifier:start_link( fun({_, DbName0}) when DbName0 == DbName -> @@ -81,16 +82,15 @@ couch_stats_collector:track_process_count(Self, {httpd, clients_requesting_changes}), try - keep_sending_changes(Req, Resp, Db, StartSeq, <<"">>, Timeout, TimeoutFun) + keep_sending_changes(Req, Resp, Db, StartSeq, <<"">>, Timeout, TimeoutFun, ResponseType) after couch_db_update_notifier:stop(Notify), get_rest_db_updated() % clean out any remaining update messages end; - "false" -> + "normal" -> {ok, {LastSeq, _Prepend}} = send_changes(Req, Resp, Db, StartSeq, <<"">>), - send_chunk(Resp, io_lib:format("\n],\n\"last_seq\":~w}\n", [LastSeq])), - end_json_response(Resp) + end_sending_changes(Resp, LastSeq) end; handle_changes_req(#httpd{path_parts=[_,<<"_changes">>]}=Req, _Db) -> @@ -110,17 +110,25 @@ receive db_updated -> get_rest_db_updated() after 0 -> updated end. + +end_sending_changes(Resp, EndSeq) -> + send_chunk(Resp, io_lib:format("\n],\n\"last_seq\":~w}\n", [EndSeq])), + end_json_response(Resp). -keep_sending_changes(#httpd{user_ctx=UserCtx,path_parts=[DbName|_]}=Req, Resp, Db, StartSeq, Prepend, Timeout, TimeoutFun) -> +keep_sending_changes(#httpd{user_ctx=UserCtx,path_parts=[DbName|_]}=Req, Resp, Db, StartSeq, Prepend, Timeout, TimeoutFun, ResponseType) -> {ok, {EndSeq, Prepend2}} = send_changes(Req, Resp, Db, StartSeq, Prepend), couch_db:close(Db), - case wait_db_updated(Timeout, TimeoutFun) of - updated -> - {ok, Db2} = couch_db:open(DbName, [{user_ctx, UserCtx}]), - keep_sending_changes(Req, Resp, Db2, EndSeq, Prepend2, Timeout, TimeoutFun); - stop -> - send_chunk(Resp, io_lib:format("\n],\n\"last_seq\":~w}\n", [EndSeq])), - end_json_response(Resp) + if + EndSeq > StartSeq, ResponseType == "longpoll" -> + end_sending_changes(Resp, EndSeq); + true -> + case wait_db_updated(Timeout, TimeoutFun) of + updated -> + {ok, Db2} = couch_db:open(DbName, [{user_ctx, UserCtx}]), + keep_sending_changes(Req, Resp, Db2, EndSeq, Prepend2, Timeout, TimeoutFun, ResponseType); + stop -> + end_sending_changes(Resp, EndSeq) + end end. send_changes(Req, Resp, Db, StartSeq, Prepend0) ->