diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2020-11-25 16:52:41 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-11-25 23:03:46 +0000 |
commit | 82aea1d428e3a06994d6624464b74b92e47eae2d (patch) | |
tree | a8112379aafd05ba6e581d22d4d5584b0cb7b8e9 /src/mongo/db/views | |
parent | a194505325087b1e841fdee55c51312a042ce9d2 (diff) | |
download | mongo-82aea1d428e3a06994d6624464b74b92e47eae2d.tar.gz |
SERVER-52523 Implement in-memory time-series bucket catalog
Diffstat (limited to 'src/mongo/db/views')
-rw-r--r-- | src/mongo/db/views/durable_view_catalog.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/views/view.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/views/view.h | 11 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog.cpp | 32 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog.h | 6 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog_test.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/views/view_definition_test.cpp | 37 | ||||
-rw-r--r-- | src/mongo/db/views/view_graph_test.cpp | 2 |
8 files changed, 84 insertions, 32 deletions
diff --git a/src/mongo/db/views/durable_view_catalog.cpp b/src/mongo/db/views/durable_view_catalog.cpp index 1031f87682f..d6770ca7a99 100644 --- a/src/mongo/db/views/durable_view_catalog.cpp +++ b/src/mongo/db/views/durable_view_catalog.cpp @@ -142,7 +142,8 @@ BSONObj DurableViewCatalogImpl::_validateViewDefinition(OperationContext* opCtx, for (const BSONElement& e : viewDefinition) { std::string name(e.fieldName()); - valid &= name == "_id" || name == "viewOn" || name == "pipeline" || name == "collation"; + valid &= name == "_id" || name == "viewOn" || name == "pipeline" || name == "collation" || + name == "timeseries"; } const auto viewName = viewDefinition["_id"].str(); @@ -168,6 +169,9 @@ BSONObj DurableViewCatalogImpl::_validateViewDefinition(OperationContext* opCtx, valid &= (!viewDefinition.hasField("collation") || viewDefinition["collation"].type() == BSONType::Object); + valid &= !viewDefinition.hasField("timeseries") || + viewDefinition["timeseries"].type() == BSONType::Object; + uassert(ErrorCodes::InvalidViewDefinition, str::stream() << "found invalid view definition " << viewDefinition["_id"] << " while reading '" << _db->getSystemViewsName() << "'", diff --git a/src/mongo/db/views/view.cpp b/src/mongo/db/views/view.cpp index e5812dedf19..1f2f6d797bd 100644 --- a/src/mongo/db/views/view.cpp +++ b/src/mongo/db/views/view.cpp @@ -41,8 +41,12 @@ ViewDefinition::ViewDefinition(StringData dbName, StringData viewName, StringData viewOnName, const BSONObj& pipeline, - std::unique_ptr<CollatorInterface> collator) - : _viewNss(dbName, viewName), _viewOnNss(dbName, viewOnName), _collator(std::move(collator)) { + std::unique_ptr<CollatorInterface> collator, + const boost::optional<TimeseriesOptions>& timeseries) + : _viewNss(dbName, viewName), + _viewOnNss(dbName, viewOnName), + _collator(std::move(collator)), + _timeseries(timeseries) { for (BSONElement e : pipeline) { _pipeline.push_back(e.Obj().getOwned()); } @@ -52,22 +56,19 @@ ViewDefinition::ViewDefinition(const ViewDefinition& other) : _viewNss(other._viewNss), _viewOnNss(other._viewOnNss), _collator(CollatorInterface::cloneCollator(other._collator.get())), - _pipeline(other._pipeline) {} + _pipeline(other._pipeline), + _timeseries(other._timeseries) {} ViewDefinition& ViewDefinition::operator=(const ViewDefinition& other) { _viewNss = other._viewNss; _viewOnNss = other._viewOnNss; _collator = CollatorInterface::cloneCollator(other._collator.get()); _pipeline = other._pipeline; + _timeseries = other._timeseries; return *this; } -bool ViewDefinition::isTimeseries() const { - auto bucketsNs = _viewNss.makeTimeseriesBucketsNamespace(); - return bucketsNs == _viewOnNss; -} - void ViewDefinition::setViewOn(const NamespaceString& viewOnNss) { invariant(_viewNss.db() == viewOnNss.db()); _viewOnNss = viewOnNss; diff --git a/src/mongo/db/views/view.h b/src/mongo/db/views/view.h index 715399ef746..07edd41fddc 100644 --- a/src/mongo/db/views/view.h +++ b/src/mongo/db/views/view.h @@ -36,6 +36,7 @@ #include "mongo/bson/bsonobj.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/collation/collator_interface.h" +#include "mongo/db/timeseries/timeseries_gen.h" namespace mongo { @@ -52,7 +53,8 @@ public: StringData viewName, StringData viewOnName, const BSONObj& pipeline, - std::unique_ptr<CollatorInterface> collation); + std::unique_ptr<CollatorInterface> collation, + const boost::optional<TimeseriesOptions>& timeseries); /** * Copying a view 'other' clones its collator and does a simple copy of all other fields. @@ -91,9 +93,11 @@ public: } /** - * Returns true if this view represents a time-series collection. + * Returns the time-series options for the view, or boost::none if not a time-series view. */ - bool isTimeseries() const; + const boost::optional<TimeseriesOptions>& timeseries() const { + return _timeseries; + } void setViewOn(const NamespaceString& viewOnNss); @@ -107,5 +111,6 @@ private: NamespaceString _viewOnNss; std::unique_ptr<CollatorInterface> _collator; std::vector<BSONObj> _pipeline; + boost::optional<TimeseriesOptions> _timeseries; }; } // namespace mongo diff --git a/src/mongo/db/views/view_catalog.cpp b/src/mongo/db/views/view_catalog.cpp index c606eede46a..a20cec26e77 100644 --- a/src/mongo/db/views/view_catalog.cpp +++ b/src/mongo/db/views/view_catalog.cpp @@ -122,11 +122,22 @@ Status ViewCatalog::_reload(WithLock, } } + boost::optional<TimeseriesOptions> timeseries; + if (view.hasField("timeseries")) { + try { + timeseries = + TimeseriesOptions::parse({"ViewCatalog::_reload"}, view["timeseries"].Obj()); + } catch (const DBException& ex) { + return ex.toStatus(); + } + } + _viewMap[viewName.ns()] = std::make_shared<ViewDefinition>(viewName.db(), viewName.coll(), view["viewOn"].str(), pipeline, - std::move(collator.getValue())); + std::move(collator.getValue()), + timeseries); return Status::OK(); }; @@ -185,7 +196,8 @@ Status ViewCatalog::_createOrUpdateView(WithLock lk, const NamespaceString& viewName, const NamespaceString& viewOn, const BSONArray& pipeline, - std::unique_ptr<CollatorInterface> collator) { + std::unique_ptr<CollatorInterface> collator, + const boost::optional<TimeseriesOptions>& timeseries) { invariant(opCtx->lockState()->isDbLockedForMode(viewName.db(), MODE_IX)); invariant(opCtx->lockState()->isCollectionLockedForMode(viewName, MODE_IX)); invariant(opCtx->lockState()->isCollectionLockedForMode( @@ -206,10 +218,17 @@ Status ViewCatalog::_createOrUpdateView(WithLock lk, if (collator) { viewDefBuilder.append("collation", collator->getSpec().toBSON()); } + if (timeseries) { + viewDefBuilder.append("timeseries", timeseries->toBSON()); + } BSONObj ownedPipeline = pipeline.getOwned(); - auto view = std::make_shared<ViewDefinition>( - viewName.db(), viewName.coll(), viewOn.coll(), ownedPipeline, std::move(collator)); + auto view = std::make_shared<ViewDefinition>(viewName.db(), + viewName.coll(), + viewOn.coll(), + ownedPipeline, + std::move(collator), + timeseries); // Check that the resulting dependency graph is acyclic and within the maximum depth. Status graphStatus = _upsertIntoGraph(lk, opCtx, *(view.get())); @@ -403,7 +422,8 @@ Status ViewCatalog::createView(OperationContext* opCtx, const NamespaceString& viewName, const NamespaceString& viewOn, const BSONArray& pipeline, - const BSONObj& collation) { + const BSONObj& collation, + const boost::optional<TimeseriesOptions>& timeseries) { invariant(opCtx->lockState()->isDbLockedForMode(viewName.db(), MODE_IX)); invariant(opCtx->lockState()->isCollectionLockedForMode(viewName, MODE_IX)); invariant(opCtx->lockState()->isCollectionLockedForMode( @@ -428,7 +448,7 @@ Status ViewCatalog::createView(OperationContext* opCtx, return collator.getStatus(); return _createOrUpdateView( - lk, opCtx, viewName, viewOn, pipeline, std::move(collator.getValue())); + lk, opCtx, viewName, viewOn, pipeline, std::move(collator.getValue()), timeseries); } Status ViewCatalog::modifyView(OperationContext* opCtx, diff --git a/src/mongo/db/views/view_catalog.h b/src/mongo/db/views/view_catalog.h index ecfff9de990..46a6735cf9c 100644 --- a/src/mongo/db/views/view_catalog.h +++ b/src/mongo/db/views/view_catalog.h @@ -102,7 +102,8 @@ public: const NamespaceString& viewName, const NamespaceString& viewOn, const BSONArray& pipeline, - const BSONObj& collation); + const BSONObj& collation, + const boost::optional<TimeseriesOptions>& timeseries); /** * Drop the view named 'viewName'. @@ -168,7 +169,8 @@ private: const NamespaceString& viewName, const NamespaceString& viewOn, const BSONArray& pipeline, - std::unique_ptr<CollatorInterface> collator); + std::unique_ptr<CollatorInterface> collator, + const boost::optional<TimeseriesOptions>& timeseries = boost::none); /** * Parses the view definition pipeline, attempts to upsert into the view graph, and refreshes * the graph if necessary. Returns an error status if the resulting graph would be invalid. diff --git a/src/mongo/db/views/view_catalog_test.cpp b/src/mongo/db/views/view_catalog_test.cpp index c2d7367db3e..30d1b396444 100644 --- a/src/mongo/db/views/view_catalog_test.cpp +++ b/src/mongo/db/views/view_catalog_test.cpp @@ -123,7 +123,8 @@ public: MODE_X); WriteUnitOfWork wuow(opCtx); - Status s = _viewCatalog->createView(opCtx, viewName, viewOn, pipeline, collation); + Status s = + _viewCatalog->createView(opCtx, viewName, viewOn, pipeline, collation, boost::none); wuow.commit(); return s; @@ -530,7 +531,7 @@ TEST_F(ViewCatalogFixture, LookupRIDExistingViewRollback) { WriteUnitOfWork wunit(operationContext()); ASSERT_OK(getViewCatalog()->createView( - operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); + operationContext(), viewName, viewOn, emptyPipeline, emptyCollation, boost::none)); } auto resourceID = ResourceId(RESOURCE_COLLECTION, "db.view"_sd); auto collectionCatalog = CollectionCatalog::get(operationContext()); diff --git a/src/mongo/db/views/view_definition_test.cpp b/src/mongo/db/views/view_definition_test.cpp index 6b2aa57cba9..7ea401caee4 100644 --- a/src/mongo/db/views/view_definition_test.cpp +++ b/src/mongo/db/views/view_definition_test.cpp @@ -47,10 +47,11 @@ namespace { const NamespaceString viewNss("testdb.testview"); const NamespaceString backingNss("testdb.testcoll"); const BSONObj samplePipeline = BSON_ARRAY(BSON("limit" << 9)); +const TimeseriesOptions timeseries("time"); TEST(ViewDefinitionTest, ViewDefinitionCreationCorrectlyBuildsNamespaceStrings) { ViewDefinition viewDef( - viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr); + viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr, boost::none); ASSERT_EQ(viewDef.name(), viewNss); ASSERT_EQ(viewDef.viewOn(), backingNss); } @@ -58,8 +59,12 @@ TEST(ViewDefinitionTest, ViewDefinitionCreationCorrectlyBuildsNamespaceStrings) TEST(ViewDefinitionTest, CopyConstructorProperlyClonesAllFields) { auto collator = std::make_unique<CollatorInterfaceMock>(CollatorInterfaceMock::MockType::kReverseString); - ViewDefinition originalView( - viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, std::move(collator)); + ViewDefinition originalView(viewNss.db(), + viewNss.coll(), + backingNss.coll(), + samplePipeline, + std::move(collator), + timeseries); ViewDefinition copiedView(originalView); ASSERT_EQ(originalView.name(), copiedView.name()); @@ -70,13 +75,18 @@ TEST(ViewDefinitionTest, CopyConstructorProperlyClonesAllFields) { SimpleBSONObjComparator::kInstance.makeEqualTo())); ASSERT(CollatorInterface::collatorsMatch(originalView.defaultCollator(), copiedView.defaultCollator())); + ASSERT(originalView.timeseries()->toBSON().binaryEqual(copiedView.timeseries()->toBSON())); } TEST(ViewDefinitionTest, CopyAssignmentOperatorProperlyClonesAllFields) { auto collator = std::make_unique<CollatorInterfaceMock>(CollatorInterfaceMock::MockType::kReverseString); - ViewDefinition originalView( - viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, std::move(collator)); + ViewDefinition originalView(viewNss.db(), + viewNss.coll(), + backingNss.coll(), + samplePipeline, + std::move(collator), + timeseries); ViewDefinition copiedView = originalView; ASSERT_EQ(originalView.name(), copiedView.name()); @@ -87,20 +97,21 @@ TEST(ViewDefinitionTest, CopyAssignmentOperatorProperlyClonesAllFields) { SimpleBSONObjComparator::kInstance.makeEqualTo())); ASSERT(CollatorInterface::collatorsMatch(originalView.defaultCollator(), copiedView.defaultCollator())); + ASSERT(originalView.timeseries()->toBSON().binaryEqual(copiedView.timeseries()->toBSON())); } DEATH_TEST_REGEX(ViewDefinitionTest, SetViewOnFailsIfNewViewOnNotInSameDatabaseAsView, R"#(Invariant failure.*_viewNss.db\(\) == viewOnNss.db\(\))#") { ViewDefinition viewDef( - viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr); + viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr, boost::none); NamespaceString badViewOn("someOtherDb.someOtherCollection"); viewDef.setViewOn(badViewOn); } TEST(ViewDefinitionTest, SetViewOnSucceedsIfNewViewOnIsInSameDatabaseAsView) { ViewDefinition viewDef( - viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr); + viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr, boost::none); ASSERT_EQ(viewDef.viewOn(), backingNss); NamespaceString newViewOn("testdb.othercollection"); @@ -112,7 +123,7 @@ DEATH_TEST_REGEX(ViewDefinitionTest, SetPiplineFailsIfPipelineTypeIsNotArray, R"#(Invariant failure.*pipeline.type\(\) == Array)#") { ViewDefinition viewDef( - viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr); + viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr, boost::none); // We'll pass in a BSONElement that could be a valid array, but is BSONType::Object rather than // BSONType::Array. @@ -127,7 +138,8 @@ DEATH_TEST_REGEX(ViewDefinitionTest, } TEST(ViewDefinitionTest, SetPipelineSucceedsOnValidArrayBSONElement) { - ViewDefinition viewDef(viewNss.db(), viewNss.coll(), backingNss.coll(), BSONObj(), nullptr); + ViewDefinition viewDef( + viewNss.db(), viewNss.coll(), backingNss.coll(), BSONObj(), nullptr, boost::none); ASSERT(viewDef.pipeline().empty()); BSONObj matchStage = BSON("match" << BSON("x" << 9)); @@ -142,5 +154,12 @@ TEST(ViewDefinitionTest, SetPipelineSucceedsOnValidArrayBSONElement) { viewDef.pipeline().begin(), SimpleBSONObjComparator::kInstance.makeEqualTo())); } + +TEST(ViewDefinitionTest, ViewDefinitionCreationCorrectlySetsTimeseries) { + ViewDefinition viewDef( + viewNss.db(), viewNss.coll(), backingNss.coll(), samplePipeline, nullptr, timeseries); + ASSERT(viewDef.timeseries()); + ASSERT_EQ(viewDef.timeseries()->getTimeField(), "time"); +} } // namespace } // namespace mongo diff --git a/src/mongo/db/views/view_graph_test.cpp b/src/mongo/db/views/view_graph_test.cpp index 5ace80ef15a..0dbdab653d4 100644 --- a/src/mongo/db/views/view_graph_test.cpp +++ b/src/mongo/db/views/view_graph_test.cpp @@ -83,7 +83,7 @@ public: collator = std::move(factoryCollator.getValue()); } - return {db, view, viewOn, pipeline, std::move(collator)}; + return {db, view, viewOn, pipeline, std::move(collator), boost::none}; } private: |