summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ. Rassi <rassi@10gen.com>2016-06-22 16:26:09 -0400
committerJ. Rassi <rassi@10gen.com>2016-06-27 16:04:32 -0400
commitcd9cef182e0e9046df6233380350c5009278f8aa (patch)
tree4df7783260743419214afbe34c3b69f6dfe19836
parentabf863ca0f05b7d9db4f2c92b89dcfdff45572f1 (diff)
downloadmongo-cd9cef182e0e9046df6233380350c5009278f8aa.tar.gz
SERVER-24703 Improved DBClientWithCommands index creation method
C++ driver SHAs cherry-picked (with modifications) into this commit: d67f5b5
-rw-r--r--src/mongo/bson/bson_field.h2
-rw-r--r--src/mongo/client/SConscript11
-rw-r--r--src/mongo/client/dbclient.cpp49
-rw-r--r--src/mongo/client/dbclientinterface.h38
-rw-r--r--src/mongo/client/index_spec.cpp239
-rw-r--r--src/mongo/client/index_spec.h220
-rw-r--r--src/mongo/client/index_spec_test.cpp91
-rw-r--r--src/mongo/dbtests/clienttests.cpp157
-rw-r--r--src/mongo/dbtests/documentsourcetests.cpp6
-rw-r--r--src/mongo/shell/bench.cpp2
10 files changed, 759 insertions, 56 deletions
diff --git a/src/mongo/bson/bson_field.h b/src/mongo/bson/bson_field.h
index 16f3cff72ab..7faa144bc86 100644
--- a/src/mongo/bson/bson_field.h
+++ b/src/mongo/bson/bson_field.h
@@ -65,8 +65,6 @@ namespace mongo {
* In a query:
* conn->findOne(myColl, BSON(MyCollFields::count.gt(10))) ;
*
- * In a command:
- * conn->ensureIndex(mycoll, BSON(MyCollFields::draining() << 1), true);
*/
template <typename T>
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript
index 4134ed14548..a01d60ffe87 100644
--- a/src/mongo/client/SConscript
+++ b/src/mongo/client/SConscript
@@ -140,6 +140,7 @@ env.Library(
'dbclient.cpp',
'dbclient_rs.cpp',
'dbclientcursor.cpp',
+ 'index_spec.cpp',
'global_conn_pool.cpp',
'replica_set_monitor.cpp',
'replica_set_monitor_manager.cpp',
@@ -237,6 +238,16 @@ env.CppUnitTest('dbclient_rs_test',
)
env.CppUnitTest(
+ target='index_spec_test',
+ source=[
+ 'index_spec_test.cpp',
+ ],
+ LIBDEPS=[
+ 'clientdriver',
+ ],
+)
+
+env.CppUnitTest(
target='scoped_db_conn_test',
source=[
'scoped_db_conn_test.cpp',
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp
index 28b99a1e708..8a76a95de26 100644
--- a/src/mongo/client/dbclient.cpp
+++ b/src/mongo/client/dbclient.cpp
@@ -1233,42 +1233,23 @@ string DBClientWithCommands::genIndexName(const BSONObj& keys) {
return ss.str();
}
-void DBClientWithCommands::ensureIndex(const string& ns,
- BSONObj keys,
- bool unique,
- const string& name,
- bool background,
- int version,
- int ttl) {
- BSONObjBuilder toSave;
- toSave.append("ns", ns);
- toSave.append("key", keys);
-
- string cacheKey(ns);
- cacheKey += "--";
-
- if (name != "") {
- toSave.append("name", name);
- cacheKey += name;
- } else {
- string nn = genIndexName(keys);
- toSave.append("name", nn);
- cacheKey += nn;
+void DBClientWithCommands::createIndex(StringData ns, const IndexSpec& descriptor) {
+ const BSONObj descriptorObj = descriptor.toBSON();
+
+ BSONObjBuilder command;
+ command.append("createIndexes", nsToCollectionSubstring(ns));
+ {
+ BSONArrayBuilder indexes(command.subarrayStart("indexes"));
+ indexes.append(descriptorObj);
}
+ const BSONObj commandObj = command.done();
- if (version >= 0)
- toSave.append("v", version);
-
- if (unique)
- toSave.appendBool("unique", unique);
-
- if (background)
- toSave.appendBool("background", true);
-
- if (ttl > 0)
- toSave.append("expireAfterSeconds", ttl);
-
- insert(NamespaceString(ns).getSystemIndexesCollection(), toSave.obj());
+ BSONObj infoObj;
+ if (!runCommand(nsToDatabase(ns), commandObj, infoObj)) {
+ Status runCommandStatus = getStatusFromCommandResult(infoObj);
+ invariant(!runCommandStatus.isOK());
+ uassertStatusOK(runCommandStatus);
+ }
}
/* -- DBClientCursor ---------------------------------------------- */
diff --git a/src/mongo/client/dbclientinterface.h b/src/mongo/client/dbclientinterface.h
index 6244db6c4ed..cc2be6c600e 100644
--- a/src/mongo/client/dbclientinterface.h
+++ b/src/mongo/client/dbclientinterface.h
@@ -32,6 +32,7 @@
#include "mongo/base/string_data.h"
#include "mongo/client/connection_string.h"
+#include "mongo/client/index_spec.h"
#include "mongo/client/query.h"
#include "mongo/client/read_preference.h"
#include "mongo/db/jsobj.h"
@@ -704,23 +705,28 @@ public:
bool exists(const std::string& ns);
- /** Create an index if it does not already exist.
- @param ns collection to be indexed
- @param keys the "key pattern" for the index. e.g., { name : 1 }
- @param unique if true, indicates that key uniqueness should be enforced for this index
- @param name if not specified, it will be created from the keys automatically (which is
- recommended)
- @param background build index in the background (see mongodb docs for details)
- @param v index version. leave at default value. (unit tests set this parameter.)
- @param ttl. The value of how many seconds before data should be removed from a collection.
+ /** Create an index on the collection 'ns' as described by the given keys. If you wish
+ * to specify options, see the more flexible overload of 'createIndex' which takes an
+ * IndexSpec object. Failure to construct the index is reported by throwing a
+ * UserException.
+ *
+ * @param ns Namespace on which to create the index
+ * @param keys Document describing keys and index types. You must provide at least one
+ * field and its direction.
+ */
+ void createIndex(StringData ns, const BSONObj& keys) {
+ return createIndex(ns, IndexSpec().addKeys(keys));
+ }
+
+ /** Create an index on the collection 'ns' as described by the given
+ * descriptor. Failure to construct the index is reported by throwing a
+ * UserException.
+ *
+ * @param ns Namespace on which to create the index
+ * @param descriptor Configuration object describing the index to create. The
+ * descriptor must describe at least one key and index type.
*/
- virtual void ensureIndex(const std::string& ns,
- BSONObj keys,
- bool unique = false,
- const std::string& name = "",
- bool background = false,
- int v = -1,
- int ttl = 0);
+ virtual void createIndex(StringData ns, const IndexSpec& descriptor);
virtual std::list<BSONObj> getIndexSpecs(const std::string& ns, int options = 0);
diff --git a/src/mongo/client/index_spec.cpp b/src/mongo/client/index_spec.cpp
new file mode 100644
index 00000000000..bf725088496
--- /dev/null
+++ b/src/mongo/client/index_spec.cpp
@@ -0,0 +1,239 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/client/index_spec.h"
+
+#include "mongo/client/dbclientinterface.h"
+
+namespace mongo {
+
+const char IndexSpec::kIndexValText[] = "text";
+const char IndexSpec::kIndexValGeo2D[] = "2d";
+const char IndexSpec::kIndexValGeoHaystack[] = "geoHaystack";
+const char IndexSpec::kIndexValGeo2DSphere[] = "2dsphere";
+const char IndexSpec::kIndexValHashed[] = "hashed";
+
+namespace {
+
+const int kIndexTypeNumbers[] = {IndexSpec::kIndexValAscending, IndexSpec::kIndexValDescending};
+
+const char* const kIndexTypeStrings[] = {NULL,
+ NULL,
+ IndexSpec::kIndexValText,
+ IndexSpec::kIndexValGeo2D,
+ IndexSpec::kIndexValGeoHaystack,
+ IndexSpec::kIndexValGeo2DSphere,
+ IndexSpec::kIndexValHashed};
+
+const char kDuplicateKey[] = "duplicate key added to index descriptor";
+const char kDuplicateOption[] = "duplicate option added to index descriptor";
+
+} // namespace
+
+IndexSpec::IndexSpec() : _dynamicName(true) {}
+
+IndexSpec& IndexSpec::addKey(const StringData& field, IndexType type) {
+ uassert(ErrorCodes::InvalidOptions, kDuplicateKey, !_keys.asTempObj().hasField(field));
+ if (type <= kIndexTypeDescending)
+ _keys.append(field, kIndexTypeNumbers[type]);
+ else
+ _keys.append(field, kIndexTypeStrings[type]);
+ _rename();
+ return *this;
+}
+
+IndexSpec& IndexSpec::addKey(const BSONElement& fieldAndType) {
+ uassert(ErrorCodes::InvalidOptions,
+ kDuplicateKey,
+ !_keys.asTempObj().hasField(fieldAndType.fieldName()));
+ _keys.append(fieldAndType);
+ _rename();
+ return *this;
+}
+
+IndexSpec& IndexSpec::addKeys(const KeyVector& keys) {
+ KeyVector::const_iterator where = keys.begin();
+ const KeyVector::const_iterator end = keys.end();
+ for (; where != end; ++where)
+ addKey(where->first, where->second);
+ return *this;
+}
+
+IndexSpec& IndexSpec::addKeys(const BSONObj& keys) {
+ BSONObjIterator iter(keys);
+ while (iter.more())
+ addKey(iter.next());
+ return *this;
+}
+
+IndexSpec& IndexSpec::background(bool value) {
+ uassert(
+ ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("background"));
+ _options.append("background", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::unique(bool value) {
+ uassert(ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("unique"));
+ _options.append("unique", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::name(const StringData& value) {
+ _name = value.toString();
+ _dynamicName = false;
+ return *this;
+}
+
+IndexSpec& IndexSpec::dropDuplicates(bool value) {
+ uassert(
+ ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("dropDups"));
+ _options.append("dropDups", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::sparse(bool value) {
+ uassert(ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("sparse"));
+ _options.append("sparse", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::expireAfterSeconds(int value) {
+ uassert(ErrorCodes::InvalidOptions,
+ kDuplicateOption,
+ !_options.asTempObj().hasField("expireAfterSeconds"));
+ _options.append("expireAfterSeconds", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::version(int value) {
+ uassert(ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("v"));
+ _options.append("v", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::textWeights(const BSONObj& value) {
+ uassert(
+ ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("weights"));
+ _options.append("weights", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::textDefaultLanguage(const StringData& value) {
+ uassert(ErrorCodes::InvalidOptions,
+ kDuplicateOption,
+ !_options.asTempObj().hasField("default_language"));
+ _options.append("default_language", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::textLanguageOverride(const StringData& value) {
+ uassert(ErrorCodes::InvalidOptions,
+ kDuplicateOption,
+ !_options.asTempObj().hasField("language_override"));
+ _options.append("language_override", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::textIndexVersion(int value) {
+ uassert(ErrorCodes::InvalidOptions,
+ kDuplicateOption,
+ !_options.asTempObj().hasField("textIndexVersion"));
+ _options.append("textIndexVersion", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::geo2DSphereIndexVersion(int value) {
+ uassert(ErrorCodes::InvalidOptions,
+ kDuplicateOption,
+ !_options.asTempObj().hasField("2dsphereIndexVersion"));
+ _options.append("2dsphereIndexVersion", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::geo2DBits(int value) {
+ uassert(ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("bits"));
+ _options.append("bits", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::geo2DMin(double value) {
+ uassert(ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("min"));
+ _options.append("min", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::geo2DMax(double value) {
+ uassert(ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("max"));
+ _options.append("max", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::geoHaystackBucketSize(double value) {
+ uassert(
+ ErrorCodes::InvalidOptions, kDuplicateOption, !_options.asTempObj().hasField("bucketSize"));
+ _options.append("bucketSize", value);
+ return *this;
+}
+
+IndexSpec& IndexSpec::addOption(const BSONElement& option) {
+ uassert(ErrorCodes::InvalidOptions,
+ kDuplicateOption,
+ !_options.asTempObj().hasField(option.fieldName()));
+ _options.append(option);
+ return *this;
+}
+
+IndexSpec& IndexSpec::addOptions(const BSONObj& options) {
+ BSONObjIterator iter(options);
+ while (iter.more())
+ addOption(iter.next());
+ return *this;
+}
+
+std::string IndexSpec::name() const {
+ return _name;
+}
+
+BSONObj IndexSpec::toBSON() const {
+ BSONObjBuilder bob;
+ bob.append("name", name());
+ bob.append("key", _keys.asTempObj());
+ bob.appendElements(_options.asTempObj());
+ return bob.obj();
+}
+
+void IndexSpec::_rename() {
+ if (!_dynamicName)
+ return;
+ _name = DBClientWithCommands::genIndexName(_keys.asTempObj());
+}
+
+} // namespace mongo
diff --git a/src/mongo/client/index_spec.h b/src/mongo/client/index_spec.h
new file mode 100644
index 00000000000..17154acdfef
--- /dev/null
+++ b/src/mongo/client/index_spec.h
@@ -0,0 +1,220 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "mongo/db/jsobj.h"
+
+namespace mongo {
+
+class StringData;
+
+class IndexSpec {
+public:
+ // An enumeration of symbolic names for index types.
+ enum IndexType {
+ kIndexTypeAscending,
+ kIndexTypeDescending,
+ kIndexTypeText,
+ kIndexTypeGeo2D,
+ kIndexTypeGeoHaystack,
+ kIndexTypeGeo2DSphere,
+ kIndexTypeHashed,
+ };
+
+ // The values to be encoded in BSON for each type of index.
+ static const int kIndexValAscending = 1;
+ static const int kIndexValDescending = -1;
+ static const char kIndexValText[];
+ static const char kIndexValGeo2D[];
+ static const char kIndexValGeoHaystack[];
+ static const char kIndexValGeo2DSphere[];
+ static const char kIndexValHashed[];
+
+ /** Create a new IndexSpec. */
+ IndexSpec();
+
+ //
+ // Methods for adding keys. Methods on this class will prevent you from adding a given
+ // key multiple times. Constraints on the validity of compound indexes are not enforced
+ // here.
+ //
+
+ /** Add a new component, by default ascending, field to index. */
+ IndexSpec& addKey(const StringData& field, IndexType type = kIndexTypeAscending);
+
+ /** Add a component to this index. The field name of the element is used as the field
+ * name to index. The value of the element is the index type. This method exists to
+ * accomodate building future index types for which the enumeration value has not yet
+ * been extended.
+ */
+ IndexSpec& addKey(const BSONElement& fieldAndType);
+
+ /** Add all components in the provided key vector to the index descriptor. */
+ typedef std::vector<std::pair<std::string, IndexType>> KeyVector;
+ IndexSpec& addKeys(const KeyVector& keys);
+
+ /** Add all keys from the provided object to the index descriptor. */
+ IndexSpec& addKeys(const BSONObj& keys);
+
+
+ //
+ // Methods for adding options. As for keys, duplicated settings are checked and will
+ // raise an error.
+ //
+
+ //
+ // Common index options
+ //
+
+ /** Controls whether this index should be built in the foreground or background. By
+ * default indexes are built in the foreground.
+ */
+ IndexSpec& background(bool value = true);
+
+ /** Set whether or not this index should enforce uniqueness. By default, uniqueness is
+ * not enforced.
+ */
+ IndexSpec& unique(bool value = true);
+
+
+ /** Set the name for this index. If not set, a name will be automatically generated. */
+ IndexSpec& name(const StringData& name);
+
+ /** Sets whether duplicates detected while indexing should be dropped. By default,
+ * duplicates are not dropped.
+ */
+ IndexSpec& dropDuplicates(bool value = true);
+
+ /** Sets whether or not this index should be sparse. By default, indexes are not
+ * sparse.
+ */
+ IndexSpec& sparse(bool value = true);
+
+ /** Enables time-to-live semantics for this index with the specified lifetime in
+ * seconds. Note that the indexed field must be of type UTC datetime for this option
+ * to work correctly.
+ */
+ IndexSpec& expireAfterSeconds(int value);
+
+ /** Explicitly request an index of the given version. As of MongoDB 2.6, the only accepted
+ * values are 0 or 1. Versions 2.0 and later default to '1'. Do not set this option except
+ * in unusual circumstances.
+ */
+ IndexSpec& version(int value);
+
+
+ //
+ // Text options
+ //
+
+ /** Sets the 'weights' document for a text index. */
+ IndexSpec& textWeights(const BSONObj& value);
+
+ /** Sets the default language for a text index. */
+ IndexSpec& textDefaultLanguage(const StringData& value);
+
+ /** Sets the name of the field containing the language override in a text index. */
+ IndexSpec& textLanguageOverride(const StringData& value);
+
+ /** Sets the version of the text index to use. MongoDB 2.4 only supports version
+ * '1'. If not otherwise specified, MongoDB 2.6 defaults to version 2.
+ */
+ IndexSpec& textIndexVersion(int value);
+
+
+ //
+ // 2D Sphere Options
+ //
+
+ /** Sets the version of the 2D sphere index to use. MongoDB 2.4 only supports version
+ * '1'. If not otherwise specified, MongoDB 2.6 defaults to version 2.
+ */
+ IndexSpec& geo2DSphereIndexVersion(int value);
+
+
+ //
+ // Geo2D Options
+ //
+
+ /** Sets the number of bits of precision for geohash. */
+ IndexSpec& geo2DBits(int value);
+
+ /** Sets the minimum value for keys in a geo2d index. */
+ IndexSpec& geo2DMin(double value);
+
+ /** Sets the maximum value for keys in a geo2d index. */
+ IndexSpec& geo2DMax(double value);
+
+
+ //
+ // Geo Haystack Options
+ //
+
+ /** Sets the bucket size for haystack indexes. */
+ IndexSpec& geoHaystackBucketSize(double value);
+
+
+ //
+ // Support for adding generic options. This is here so that if new index options
+ // become available on the server those options can be set independently of the
+ // named methods above.
+ //
+
+ /** Adds another option verbatim. */
+ IndexSpec& addOption(const BSONElement& option);
+
+ /** Adds the provided options verbatim. */
+ IndexSpec& addOptions(const BSONObj& options);
+
+ /** Get a copy of the current name for this index. If a name was provided to the
+ * constructor, a copy of this name is returned. Otherwise, the current auto-generated
+ * name given the set of indexes will be returned. Note that this is a copy:
+ * subsequent changes to the indexed fields will not affect the value returned here,
+ * and you must call 'name' again to obtain the updated value.
+ */
+ std::string name() const;
+
+ /** Return a BSONObj that captures the selected index keys and options. */
+ BSONObj toBSON() const;
+
+private:
+ void _rename();
+
+ std::string _name;
+ bool _dynamicName;
+
+ mutable BSONObjBuilder _keys;
+ mutable BSONObjBuilder _options;
+};
+
+} // namespace mongo
diff --git a/src/mongo/client/index_spec_test.cpp b/src/mongo/client/index_spec_test.cpp
new file mode 100644
index 00000000000..65821df91e5
--- /dev/null
+++ b/src/mongo/client/index_spec_test.cpp
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/client/index_spec.h"
+
+#include "mongo/unittest/unittest.h"
+
+#define ASSERT_UASSERTS(STATEMENT) ASSERT_THROWS(STATEMENT, UserException)
+
+namespace mongo {
+
+TEST(Options, RepeatedOptionsFail) {
+ ASSERT_UASSERTS(IndexSpec().background().background());
+ ASSERT_UASSERTS(IndexSpec().unique().unique());
+ ASSERT_UASSERTS(IndexSpec().dropDuplicates().dropDuplicates());
+ ASSERT_UASSERTS(IndexSpec().sparse().sparse());
+ ASSERT_UASSERTS(IndexSpec().expireAfterSeconds(1).expireAfterSeconds(1));
+ ASSERT_UASSERTS(IndexSpec().version(0).version(0));
+ ASSERT_UASSERTS(IndexSpec().textWeights(BSONObj()).textWeights(BSONObj()));
+ ASSERT_UASSERTS(IndexSpec().textDefaultLanguage("foo").textDefaultLanguage("foo"));
+ ASSERT_UASSERTS(IndexSpec().textLanguageOverride("foo").textLanguageOverride("foo"));
+ ASSERT_UASSERTS(IndexSpec().textIndexVersion(0).textIndexVersion(0));
+ ASSERT_UASSERTS(IndexSpec().geo2DSphereIndexVersion(0).geo2DSphereIndexVersion(0));
+ ASSERT_UASSERTS(IndexSpec().geo2DBits(0).geo2DBits(0));
+ ASSERT_UASSERTS(IndexSpec().geo2DMin(2.00).geo2DMin(2.00));
+ ASSERT_UASSERTS(IndexSpec().geo2DMax(2.00).geo2DMax(2.00));
+ ASSERT_UASSERTS(IndexSpec().geoHaystackBucketSize(2.0).geoHaystackBucketSize(2.0));
+ ASSERT_UASSERTS(IndexSpec().addOptions(BSON("foo" << 1 << "foo" << 1)));
+ ASSERT_UASSERTS(IndexSpec().sparse(0).addOptions(BSON("sparse" << 1)));
+}
+
+TEST(Options, RepeatedKeysFail) {
+
+ IndexSpec spec;
+ spec.addKey("aField");
+
+ ASSERT_UASSERTS(spec.addKey("aField"));
+
+ const BSONObj fields = BSON("someField" << 1 << "aField" << 1 << "anotherField" << 1);
+ ASSERT_UASSERTS(spec.addKey(fields.getField("aField")));
+ ASSERT_UASSERTS(spec.addKeys(fields));
+}
+
+TEST(Options, NameIsHonored) {
+ IndexSpec spec;
+ spec.addKey("aField");
+
+ // Should get an auto generated name
+ ASSERT_FALSE(spec.name().empty());
+
+ // That is not the name we are about to set.
+ ASSERT_NE("someName", spec.name());
+
+ spec.name("someName");
+
+ // Should get the name we specified.
+ ASSERT_EQ("someName", spec.name());
+
+ // Name can be changed as many times as we want
+ spec.name("yetAnotherName");
+ ASSERT_EQ("yetAnotherName", spec.name());
+}
+
+} // namespace mongo
diff --git a/src/mongo/dbtests/clienttests.cpp b/src/mongo/dbtests/clienttests.cpp
index 7764f5697c1..9cb2d0b70c1 100644
--- a/src/mongo/dbtests/clienttests.cpp
+++ b/src/mongo/dbtests/clienttests.cpp
@@ -233,6 +233,153 @@ public:
}
};
+class CreateSimpleV1Index : public Base {
+public:
+ CreateSimpleV1Index() : Base("CreateSimpleV1Index") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(), IndexSpec().addKey("aField").version(1));
+ }
+};
+
+class CreateSimpleNamedV1Index : public Base {
+public:
+ CreateSimpleNamedV1Index() : Base("CreateSimpleNamedV1Index") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(), IndexSpec().addKey("aField").version(1).name("aFieldV1Index"));
+ }
+};
+
+class CreateCompoundNamedV1Index : public Base {
+public:
+ CreateCompoundNamedV1Index() : Base("CreateCompoundNamedV1Index") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(),
+ IndexSpec()
+ .addKey("aField")
+ .addKey("bField", IndexSpec::kIndexTypeDescending)
+ .version(1)
+ .name("aFieldbFieldV1Index"));
+ }
+};
+
+class CreateUniqueSparseDropDupsIndexInBackground : public Base {
+public:
+ CreateUniqueSparseDropDupsIndexInBackground()
+ : Base("CreateUniqueSparseDropDupsIndexInBackground") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(
+ ns(), IndexSpec().addKey("aField").background().unique().sparse().dropDuplicates());
+ }
+};
+
+class CreateComplexTextIndex : public Base {
+public:
+ CreateComplexTextIndex() : Base("CreateComplexTextIndex") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(),
+ IndexSpec()
+ .addKey("aField", IndexSpec::kIndexTypeText)
+ .addKey("bField", IndexSpec::kIndexTypeText)
+ .textWeights(BSON("aField" << 100))
+ .textDefaultLanguage("spanish")
+ .textLanguageOverride("lang")
+ .textIndexVersion(2));
+ }
+};
+
+class Create2DIndex : public Base {
+public:
+ Create2DIndex() : Base("Create2DIndex") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(),
+ IndexSpec()
+ .addKey("aField", IndexSpec::kIndexTypeGeo2D)
+ .geo2DBits(20)
+ .geo2DMin(-120.0)
+ .geo2DMax(120.0));
+ }
+};
+
+class CreateHaystackIndex : public Base {
+public:
+ CreateHaystackIndex() : Base("CreateHaystackIndex") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(),
+ IndexSpec()
+ .addKey("aField", IndexSpec::kIndexTypeGeoHaystack)
+ .addKey("otherField", IndexSpec::kIndexTypeDescending)
+ .geoHaystackBucketSize(1.0));
+ }
+};
+
+class Create2DSphereIndex : public Base {
+public:
+ Create2DSphereIndex() : Base("Create2DSphereIndex") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(),
+ IndexSpec()
+ .addKey("aField", IndexSpec::kIndexTypeGeo2DSphere)
+ .geo2DSphereIndexVersion(2));
+ }
+};
+
+class CreateHashedIndex : public Base {
+public:
+ CreateHashedIndex() : Base("CreateHashedIndex") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(), IndexSpec().addKey("aField", IndexSpec::kIndexTypeHashed));
+ }
+};
+
+class CreateIndexFailure : public Base {
+public:
+ CreateIndexFailure() : Base("CreateIndexFailure") {}
+ void run() {
+ const ServiceContext::UniqueOperationContext txnPtr = cc().makeOperationContext();
+ OperationContext& txn = *txnPtr;
+ DBDirectClient db(&txn);
+
+ db.createIndex(ns(), IndexSpec().addKey("aField"));
+ ASSERT_THROWS(db.createIndex(ns(), IndexSpec().addKey("aField").unique()), UserException);
+ }
+};
+
class All : public Suite {
public:
All() : Suite("client") {}
@@ -244,6 +391,16 @@ public:
add<PushBack>();
add<Create>();
add<ConnectionStringTests>();
+ add<CreateSimpleV1Index>();
+ add<CreateSimpleNamedV1Index>();
+ add<CreateCompoundNamedV1Index>();
+ add<CreateUniqueSparseDropDupsIndexInBackground>();
+ add<CreateComplexTextIndex>();
+ add<Create2DIndex>();
+ add<CreateHaystackIndex>();
+ add<Create2DSphereIndex>();
+ add<CreateHashedIndex>();
+ add<CreateIndexFailure>();
}
};
diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp
index 4118fa78c07..973629cdabe 100644
--- a/src/mongo/dbtests/documentsourcetests.cpp
+++ b/src/mongo/dbtests/documentsourcetests.cpp
@@ -278,7 +278,7 @@ public:
class IndexScanProvidesSortOnKeys : public Base {
public:
void run() {
- client.ensureIndex(nss.ns(), BSON("a" << 1));
+ client.createIndex(nss.ns(), BSON("a" << 1));
createSource(BSON("a" << 1));
ASSERT_EQ(source()->getOutputSorts().size(), 1U);
@@ -289,7 +289,7 @@ public:
class ReverseIndexScanProvidesSort : public Base {
public:
void run() {
- client.ensureIndex(nss.ns(), BSON("a" << -1));
+ client.createIndex(nss.ns(), BSON("a" << -1));
createSource(BSON("a" << -1));
ASSERT_EQ(source()->getOutputSorts().size(), 1U);
@@ -300,7 +300,7 @@ public:
class CompoundIndexScanProvidesMultipleSorts : public Base {
public:
void run() {
- client.ensureIndex(nss.ns(), BSON("a" << 1 << "b" << -1));
+ client.createIndex(nss.ns(), BSON("a" << 1 << "b" << -1));
createSource(BSON("a" << 1 << "b" << -1));
ASSERT_EQ(source()->getOutputSorts().size(), 2U);
diff --git a/src/mongo/shell/bench.cpp b/src/mongo/shell/bench.cpp
index ceac9b90619..7a22953c7dd 100644
--- a/src/mongo/shell/bench.cpp
+++ b/src/mongo/shell/bench.cpp
@@ -1042,7 +1042,7 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) {
}
} break;
case OpType::CREATEINDEX:
- conn->ensureIndex(op.ns, op.key, false, "", false);
+ conn->createIndex(op.ns, op.key);
break;
case OpType::DROPINDEX:
conn->dropIndex(op.ns, op.key);