From 43b5bcbc7c754550328829ba649d1353fd755efc Mon Sep 17 00:00:00 2001 From: jiangph Date: Fri, 2 Nov 2018 17:12:10 +0800 Subject: Support out-of-sync in mango when doc is deleted - under situation where the document is deleted while the mrview index for this document is not updated, the returned value from mrview is {doc,null}. There is no such consideration in Mango to cause case_clause error. This fix is to consider out-of-sync between documents in database and their index and not to cause 500 when the _find endpoint is called. --- src/mango/src/mango_cursor_view.erl | 13 ++++++++++++- src/mango/test/01-index-crud-test.py | 35 +++++++++++++++++++++++++++++++++++ src/mango/test/mango.py | 10 +++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/mango/src/mango_cursor_view.erl b/src/mango/src/mango_cursor_view.erl index 174381e4a..4d4b6e05f 100644 --- a/src/mango/src/mango_cursor_view.erl +++ b/src/mango/src/mango_cursor_view.erl @@ -229,6 +229,9 @@ view_cb({row, Row}, #mrargs{extra = Options} = Acc) -> doc = couch_util:get_value(doc, Row) }, case ViewRow#view_row.doc of + null -> + put(mango_docs_examined, get(mango_docs_examined) + 1), + maybe_send_mango_ping(); undefined -> ViewRow2 = ViewRow#view_row{ value = couch_util:get_value(value, Row) @@ -282,6 +285,11 @@ handle_message({meta, _}, Cursor) -> {ok, Cursor}; handle_message({row, Props}, Cursor) -> case doc_member(Cursor, Props) of + {ok, null, {execution_stats, ExecutionStats1}} -> + Cursor1 = Cursor#cursor { + execution_stats = ExecutionStats1 + }, + {ok, Cursor1}; {ok, Doc, {execution_stats, ExecutionStats1}} -> Cursor1 = Cursor#cursor { execution_stats = ExecutionStats1 @@ -427,7 +435,10 @@ doc_member(Cursor, RowProps) -> match_doc(Selector, Doc, ExecutionStats1); Else -> Else - end + end; + null -> + ExecutionStats1 = mango_execution_stats:incr_docs_examined(ExecutionStats), + {ok, null, {execution_stats, ExecutionStats1}} end. diff --git a/src/mango/test/01-index-crud-test.py b/src/mango/test/01-index-crud-test.py index cf5b91865..7bc090abe 100644 --- a/src/mango/test/01-index-crud-test.py +++ b/src/mango/test/01-index-crud-test.py @@ -13,8 +13,24 @@ import random import mango +import copy import unittest +DOCS = [ + { + "_id": "1", + "name": "Jimi", + "age": 10, + "cars": 1 + }, + { + "_id": "2", + "name": "kate", + "age": 8, + "cars": 0 + } +] + class IndexCrudTests(mango.DbPerClass): def setUp(self): self.db.recreate() @@ -271,6 +287,25 @@ class IndexCrudTests(mango.DbPerClass): except Exception as e: self.assertEqual(e.response.status_code, 500) + def test_out_of_sync(self): + self.db.save_docs(copy.deepcopy(DOCS)) + self.db.create_index(["age"], name="age") + + selector = { + "age": { + "$gt": 0 + }, + } + docs = self.db.find(selector, + use_index="_design/a017b603a47036005de93034ff689bbbb6a873c4") + self.assertEqual(len(docs), 2) + + self.db.delete_doc("1") + + docs1 = self.db.find(selector, stale="ok", + use_index="_design/a017b603a47036005de93034ff689bbbb6a873c4") + self.assertEqual(len(docs1), 1) + @unittest.skipUnless(mango.has_text_service(), "requires text service") class IndexCrudTextTests(mango.DbPerClass): diff --git a/src/mango/test/mango.py b/src/mango/test/mango.py index bc12bbc68..29c003cc6 100644 --- a/src/mango/test/mango.py +++ b/src/mango/test/mango.py @@ -113,6 +113,12 @@ class Database(object): r.raise_for_status() return r.json() + def delete_doc(self, docid): + r = self.sess.get(self.path(docid)) + r.raise_for_status() + original_rev = r.json()['_rev'] + self.sess.delete(self.path(docid), params={"rev": original_rev}) + def ddoc_info(self, ddocid): r = self.sess.get(self.path([ddocid, "_info"])) r.raise_for_status() @@ -220,7 +226,7 @@ class Database(object): def find(self, selector, limit=25, skip=0, sort=None, fields=None, r=1, conflicts=False, use_index=None, explain=False, - bookmark=None, return_raw=False, update=True, executionStats=False): + bookmark=None, return_raw=False, update=True, executionStats=False, stale=None): body = { "selector": selector, "use_index": use_index, @@ -239,6 +245,8 @@ class Database(object): body["update"] = False if executionStats == True: body["execution_stats"] = True + if stale is not None: + body["stale"] = stale body = json.dumps(body) if explain: path = self.path("_explain") -- cgit v1.2.1