summaryrefslogtreecommitdiff
path: root/src/mongo/db/views
diff options
context:
space:
mode:
authorGregory Noma <gregory.noma@gmail.com>2020-11-25 16:52:41 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-11-25 23:03:46 +0000
commit82aea1d428e3a06994d6624464b74b92e47eae2d (patch)
treea8112379aafd05ba6e581d22d4d5584b0cb7b8e9 /src/mongo/db/views
parenta194505325087b1e841fdee55c51312a042ce9d2 (diff)
downloadmongo-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.cpp6
-rw-r--r--src/mongo/db/views/view.cpp17
-rw-r--r--src/mongo/db/views/view.h11
-rw-r--r--src/mongo/db/views/view_catalog.cpp32
-rw-r--r--src/mongo/db/views/view_catalog.h6
-rw-r--r--src/mongo/db/views/view_catalog_test.cpp5
-rw-r--r--src/mongo/db/views/view_definition_test.cpp37
-rw-r--r--src/mongo/db/views/view_graph_test.cpp2
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: