[SERVER-27414] On mongos, cannot query view whose first stage is $collStats and is backed by another view Created: 13/Dec/16  Updated: 27/Oct/23  Resolved: 02/Aug/19

Status: Closed
Project: Core Server
Component/s: Querying
Affects Version/s: 3.4.0
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Kyle Suarez Assignee: Backlog - Query Team (Inactive)
Resolution: Gone away Votes: 0
Labels: query-44-grooming, read-only-views
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to SERVER-22541 Aggregation plan executors should be ... Closed
is related to SERVER-27269 In sharded cluster, can't read from v... Closed
Assigned Teams:
Query
Operating System: ALL
Steps To Reproduce:

db.runCommand( { create: "view", viewOn: "collection" } );
db.runCommand( { aggregate: "view", pipeline: [ { $collStats: {} } ], cursor: { batchSize: 0 } } );

Sprint: Query 2017-03-27
Participants:

 Description   

In ViewsShardingCheck, we make an assumption that the source namespace of a view must be a collection or a nonexistent namespace. But because of $collStats, it may in fact be a view, and this overeager assumption causes a failure when running a query over a view whose first stage is $collStats and whose "viewOn" is another view.

mongos> db.createView("v1", "v2", [{: {}}])
{
        "ok" : 1,
        "logicalTime" : {
                "clusterTime" : Timestamp(1491580269, 4),
                "signature" : {
                        "hash" : BinData(0,"TC4eCke2sj28GEb7y236Nspy0ZE="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1491580269, 4)
}
mongos> db.createView("v2", "c", [{: {}}])
{
        "ok" : 1,
        "logicalTime" : {
                "clusterTime" : Timestamp(1491580277, 1),
                "signature" : {
                        "hash" : BinData(0,"DYSY4YyCpNPs2tciTcRwkzusMLc="),
                        "keyId" : NumberLong(0)
                }
        }
}
mongos> db.c.insert({x: 1})
WriteResult({ "nInserted" : 1 })
mongos> db.c.find()
{ "_id" : ObjectId("58e7b57d102c4c693c576c34"), "x" : 1 }
mongos> db.v2.find()
{ "ns" : "test.c", "localTime" : ISODate("2017-04-07T15:51:32.358Z") }
mongos> db.v1.find()
Error: error: {
        "ok" : 0,
        "errmsg" : "Namespace test.v2 is a view, not a collection",
        "code" : 166,
        "codeName" : "CommandNotSupportedOnView",
        "logicalTime" : {
                "clusterTime" : Timestamp(1491580293, 1),
                "signature" : {
                        "hash" : BinData(0,"3GtlKHmzhSsEx1vHk8I0Lz5F5E8="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(0, 0)
}

Original Description

When running an aggregation on a view that starts with $collStats and has a batchSize of 0, the following error occurs:

> db.runCommand( { aggregate: "view", pipeline: [ { $collStats: {} } ], cursor: { batchSize: 0 } } )
{
        "ok" : 0,
        "errmsg" : "Aggregation has more results than fit in initial batch, but can't create cursor since collection test.view doesn't exist",
        "code" : 17391,
        "codeName" : "Location17391"
}

Either this should work as expected, or fail with a clearer error message.



 Comments   
Comment by David Storch [ 02/Aug/19 ]

As far as I can tell, this bug no longer exists:

MongoDB Enterprise mongos> db.createView("v1", "v2", [{$collStats: {}}])
{
	"ok" : 1,
	"operationTime" : Timestamp(1564757734, 5),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1564757734, 5),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
MongoDB Enterprise mongos> db.createView("v2", "coll", [])
{
	"ok" : 1,
	"operationTime" : Timestamp(1564757749, 5),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1564757749, 5),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
MongoDB Enterprise mongos> db.coll.insert({})
WriteResult({ "nInserted" : 1 })
MongoDB Enterprise mongos> db.v2.find()
{ "_id" : ObjectId("5d444ef81e6a73b6c1ebc744") }
MongoDB Enterprise mongos> db.v1.find()
{ "ns" : "test.v2", "shard" : "__unknown_name__-rs1", "host" : "storchbox:20001", "localTime" : ISODate("2019-08-02T14:56:07.479Z") }

Closing as Gone Away.

Comment by Kyle Suarez [ 07/Apr/17 ]

Alright, status update. Charlie's cursor manager fixes have wholly eliminated the problem of views with batch size 0. The remaining problem is that you can't perform an operation on a view via mongos if the view's pipeline starts with a $collStats stage and its backing namespace is another view.

mongos> db.createView("v1", "v2", [{: {}}])
{
        "ok" : 1,
        "logicalTime" : {
                "clusterTime" : Timestamp(1491580269, 4),
                "signature" : {
                        "hash" : BinData(0,"TC4eCke2sj28GEb7y236Nspy0ZE="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1491580269, 4)
}
mongos> db.createView("v2", "c", [{: {}}])
{
        "ok" : 1,
        "logicalTime" : {
                "clusterTime" : Timestamp(1491580277, 1),
                "signature" : {
                        "hash" : BinData(0,"DYSY4YyCpNPs2tciTcRwkzusMLc="),
                        "keyId" : NumberLong(0)
                }
        }
}
mongos> db.c.insert({x: 1})
WriteResult({ "nInserted" : 1 })
mongos> db.c.find()
{ "_id" : ObjectId("58e7b57d102c4c693c576c34"), "x" : 1 }
mongos> db.v2.find()
{ "ns" : "test.c", "localTime" : ISODate("2017-04-07T15:51:32.358Z") }
mongos> db.v1.find()
Error: error: {
        "ok" : 0,
        "errmsg" : "Namespace test.v2 is a view, not a collection",
        "code" : 166,
        "codeName" : "CommandNotSupportedOnView",
        "logicalTime" : {
                "clusterTime" : Timestamp(1491580293, 1),
                "signature" : {
                        "hash" : BinData(0,"3GtlKHmzhSsEx1vHk8I0Lz5F5E8="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(0, 0)
}

Note that the same code works on a standalone.

> db.createView("v1", "v2", [{: {}}])
{ "ok" : 1 }
> db.createView("v2", "c", [{: {}}])
{ "ok" : 1 }
> db.v2.find()
{ "ns" : "test.c", "localTime" : ISODate("2017-04-07T15:48:55.186Z") }
> db.v1.find()
{ "ns" : "test.v2", "localTime" : ISODate("2017-04-07T15:48:58Z") }

I've updated the ticket's description to match the current reality.

Comment by David Storch [ 03/Apr/17 ]

kyle.suarez, yeah, if this wasn't completely fixed by the global agg ownership work, then I agree that we should reopen it and mark it as "Needs Triage".

Comment by Kyle Suarez [ 03/Apr/17 ]

I believe Charlie's work to make aggregation cursors owned by the global cursor manager have fixed the most serious problems regarding views and $collStats. However, jstests/core/views/views_coll_stats.js still fails in the sharding_jscore_passthrough suite:

assert: command failed: {
	"operationTime" : Timestamp(1491226844, 11),
	"ok" : 0,
	"errmsg" : "Namespace views_coll_stats.b is a view, not a collection",
	"code" : 166,
	"codeName" : "CommandNotSupportedOnView",
	"logicalTime" : {
		"clusterTime" : Timestamp(1491226844, 11),
		"signature" : {
			"hash" : BinData(0,"Rh30yN/9DK1QsUgGGlqz3tm5MF4="),
			"keyId" : NumberLong(0)
		}
	}
} : aggregate failed
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:16:14
assert.commandWorked@src/mongo/shell/assert.js:387:5
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1319:5
@jstests/core/views/views_coll_stats.js:57:28
@jstests/core/views/views_coll_stats.js:2:2

I'm quite certain that this is due to us taking an AutoGetCollection on the view namespace in view_sharding_check.cpp, which makes an invalid assumption that the namespace is always a collection.

After fixing this, we should unblacklist views_coll_stats.js from sharding_jscore_passthrough and probably consider expanding the test coverage:

diff --git a/jstests/views/views_coll_stats.js b/jstests/views/views_coll_stats.js
index 384fa17..a557849 100644
--- a/jstests/views/views_coll_stats.js
+++ b/jstests/views/views_coll_stats.js
@@ -58,6 +58,14 @@
     checkCollStatsBelongTo(viewsDB["b"].aggregate().next(), "c");
     clear();
 
+    // Check for expected behavior when running an aggregation against a view which is a 
+    // on an identity view.
+    makeView("a", "b", [collStatsStage]);
+    makeView("b", "c", []);
+    checkCollStatsBelongTo(viewsDB["a"].latencyStats().next(), "a");
+    checkCollStatsBelongTo(viewsDB["a"].aggregate().next(), "b");
+    clear();
+
     // Assert that attempting to retrieve storageStats fails.
     makeView("a", "b");
     assert.commandFailedWithCode(

david.storch, can I reopen this ticket and send it to triage?

Comment by Charlie Swanson [ 16/Mar/17 ]

This has been resolved by work on SERVER-22541, specifically this commit.

Comment by Kyle Suarez [ 13/Dec/16 ]

This fails because when PipelineCmd::runParsed() detects that a $collStats is run against a view, it skips view resolution altogether. Then, the aggregation proceeds as usual, but on a namespace that's a view. However, views don't have a cursor manager and rely on a backing collection on which to hang the cursor, so we find ourselves out of luck with regard to constructing a cursor in this case.

Generated at Thu Feb 08 04:15:06 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.