summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjiangph <jiangph@cn.ibm.com>2018-11-02 17:12:10 +0800
committerjiangph <jiangph@cn.ibm.com>2018-11-06 15:31:01 +0800
commit43b5bcbc7c754550328829ba649d1353fd755efc (patch)
tree670d0468408ceb9d0460710286ae9b4b0d583886
parentf350d5f5de8413ffaa6c5fac6bfb19f090fbd8ec (diff)
downloadcouchdb-113045-case-clause-mango.tar.gz
Support out-of-sync in mango when doc is deleted113045-case-clause-mango
- 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.
-rw-r--r--src/mango/src/mango_cursor_view.erl13
-rw-r--r--src/mango/test/01-index-crud-test.py35
-rw-r--r--src/mango/test/mango.py10
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")