diff options
Diffstat (limited to 'src/mongo/db/catalog/create_collection.cpp')
| -rw-r--r-- | src/mongo/db/catalog/create_collection.cpp | 159 |
1 files changed, 120 insertions, 39 deletions
diff --git a/src/mongo/db/catalog/create_collection.cpp b/src/mongo/db/catalog/create_collection.cpp index 74be2bd73e4..c64decf02a3 100644 --- a/src/mongo/db/catalog/create_collection.cpp +++ b/src/mongo/db/catalog/create_collection.cpp @@ -44,7 +44,7 @@ #include "mongo/db/catalog/index_key_validate.h" #include "mongo/db/commands.h" #include "mongo/db/commands/create_gen.h" -#include "mongo/db/concurrency/write_conflict_exception.h" +#include "mongo/db/concurrency/exception_util.h" #include "mongo/db/curop.h" #include "mongo/db/db_raii.h" #include "mongo/db/index/index_descriptor.h" @@ -117,7 +117,9 @@ Status validateClusteredIndexSpec(OperationContext* opCtx, if (expireAfterSeconds) { // Not included in the indexSpec itself. - auto status = index_key_validate::validateExpireAfterSeconds(*expireAfterSeconds); + auto status = index_key_validate::validateExpireAfterSeconds( + *expireAfterSeconds, + index_key_validate::ValidateExpireAfterSecondsMode::kClusteredTTLIndex); if (!status.isOK()) { return status; } @@ -206,6 +208,117 @@ Status _createView(OperationContext* opCtx, }); } +BSONObj _generateTimeseriesValidator(StringData timeField) { + // '$jsonSchema' : { + // bsonType: 'object', + // required: ['_id', 'control', 'data'], + // properties: { + // _id: {bsonType: 'objectId'}, + // control: { + // bsonType: 'object', + // required: ['version', 'min', 'max'], + // properties: { + // version: {bsonType: 'number'}, + // min: { + // bsonType: 'object', + // required: ['%s'], + // properties: {'%s': {bsonType: 'date'}} + // }, + // max: { + // bsonType: 'object', + // required: ['%s'], + // properties: {'%s': {bsonType: 'date'}} + // }, + // closed: {bsonType: 'bool'}, + // count: {bsonType: 'number', minimum: 1}, + // }, + // additionalProperties: false, + // }, + // data: {bsonType: 'object'}, + // meta: {} + // }, + // additionalProperties: false + // } + BSONObjBuilder validator; + BSONObjBuilder schema(validator.subobjStart("$jsonSchema")); + schema.append("bsonType", "object"); + schema.append("required", + BSON_ARRAY("_id" + << "control" + << "data")); + { + BSONObjBuilder properties(schema.subobjStart("properties")); + { + BSONObjBuilder _id(properties.subobjStart("_id")); + _id.append("bsonType", "objectId"); + _id.done(); + } + { + BSONObjBuilder control(properties.subobjStart("control")); + control.append("bsonType", "object"); + control.append("required", + BSON_ARRAY("version" + << "min" + << "max")); + { + BSONObjBuilder innerProperties(control.subobjStart("properties")); + { + BSONObjBuilder version(innerProperties.subobjStart("version")); + version.append("bsonType", "number"); + version.done(); + } + { + BSONObjBuilder min(innerProperties.subobjStart("min")); + min.append("bsonType", "object"); + min.append("required", BSON_ARRAY(timeField)); + BSONObjBuilder minProperties(min.subobjStart("properties")); + BSONObjBuilder timeFieldObj(minProperties.subobjStart(timeField)); + timeFieldObj.append("bsonType", "date"); + timeFieldObj.done(); + minProperties.done(); + min.done(); + } + + { + BSONObjBuilder max(innerProperties.subobjStart("max")); + max.append("bsonType", "object"); + max.append("required", BSON_ARRAY(timeField)); + BSONObjBuilder maxProperties(max.subobjStart("properties")); + BSONObjBuilder timeFieldObj(maxProperties.subobjStart(timeField)); + timeFieldObj.append("bsonType", "date"); + timeFieldObj.done(); + maxProperties.done(); + max.done(); + } + { + BSONObjBuilder closed(innerProperties.subobjStart("closed")); + closed.append("bsonType", "bool"); + closed.done(); + } + { + BSONObjBuilder count(innerProperties.subobjStart("count")); + count.append("bsonType", "number"); + count.append("minimum", 1); + count.done(); + } + innerProperties.done(); + } + control.append("additionalProperties", false); + control.done(); + } + { + BSONObjBuilder data(properties.subobjStart("data")); + data.append("bsonType", "object"); + data.done(); + } + properties.append("meta", BSONObj{}); + properties.done(); + } + schema.append("additionalProperties", false); + schema.done(); + return validator.obj(); +} + Status _createTimeseries(OperationContext* opCtx, const NamespaceString& ns, const CollectionOptions& optionsArg) { @@ -230,46 +343,13 @@ Status _createTimeseries(OperationContext* opCtx, maxSpanSeconds == options.timeseries->getBucketMaxSpanSeconds()); options.timeseries->setBucketMaxSpanSeconds(maxSpanSeconds); + // Set the validator option to a JSON schema enforcing constraints on bucket documents. // This validation is only structural to prevent accidental corruption by users and // cannot cover all constraints. Leave the validationLevel and validationAction to their // strict/error defaults. auto timeField = options.timeseries->getTimeField(); - auto validatorObj = fromjson(fmt::sprintf(R"( -{ -'$jsonSchema' : { - bsonType: 'object', - required: ['_id', 'control', 'data'], - properties: { - _id: {bsonType: 'objectId'}, - control: { - bsonType: 'object', - required: ['version', 'min', 'max'], - properties: { - version: {bsonType: 'number'}, - min: { - bsonType: 'object', - required: ['%s'], - properties: {'%s': {bsonType: 'date'}} - }, - max: { - bsonType: 'object', - required: ['%s'], - properties: {'%s': {bsonType: 'date'}} - }, - closed: {bsonType: 'bool'} - } - }, - data: {bsonType: 'object'}, - meta: {} - }, - additionalProperties: false -} -})", - timeField, - timeField, - timeField, - timeField)); + auto validatorObj = _generateTimeseriesValidator(timeField); bool existingBucketCollectionIsCompatible = false; @@ -321,8 +401,9 @@ Status _createTimeseries(OperationContext* opCtx, // Cluster time-series buckets collections by _id. auto expireAfterSeconds = options.expireAfterSeconds; if (expireAfterSeconds) { - uassertStatusOK( - index_key_validate::validateExpireAfterSeconds(*expireAfterSeconds)); + uassertStatusOK(index_key_validate::validateExpireAfterSeconds( + *expireAfterSeconds, + index_key_validate::ValidateExpireAfterSecondsMode::kClusteredTTLIndex)); bucketsOptions.expireAfterSeconds = expireAfterSeconds; } |
