summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/SConscript2
-rw-r--r--src/mongo/db/cloner.cpp1
-rw-r--r--src/mongo/db/db.cpp3
-rw-r--r--src/mongo/db/index.cpp42
-rw-r--r--src/mongo/db/index.h3
-rw-r--r--src/mongo/db/index/2d_index_cursor.cpp1
-rw-r--r--src/mongo/db/index/btree_key_generator.cpp7
-rw-r--r--src/mongo/db/index/btree_key_generator.h6
-rw-r--r--src/mongo/db/index/catalog_hack.h29
-rw-r--r--src/mongo/db/index/emulated_cursor.h2
-rw-r--r--src/mongo/db/index/hash_access_method.cpp35
-rw-r--r--src/mongo/db/index/hash_access_method.h11
-rw-r--r--src/mongo/db/index_legacy.cpp81
-rw-r--r--src/mongo/db/index_legacy.h67
-rw-r--r--src/mongo/db/index_names.cpp16
-rw-r--r--src/mongo/db/index_names.h8
-rw-r--r--src/mongo/db/index_selection.cpp3
-rw-r--r--src/mongo/db/index_selection.h4
-rw-r--r--src/mongo/db/indexkey.cpp104
-rw-r--r--src/mongo/db/indexkey.h110
-rw-r--r--src/mongo/db/keypattern.cpp12
-rw-r--r--src/mongo/db/keypattern.h6
-rw-r--r--src/mongo/db/namespace_details.cpp2
-rw-r--r--src/mongo/db/namespace_details.h20
-rw-r--r--src/mongo/db/pdfile.cpp9
-rw-r--r--src/mongo/db/query_optimizer_internal.cpp5
-rw-r--r--src/mongo/db/query_plan.cpp6
-rw-r--r--src/mongo/db/query_plan.h1
-rw-r--r--src/mongo/db/queryutil.cpp7
-rw-r--r--src/mongo/db/queryutil.h2
-rw-r--r--src/mongo/db/scanandorder.cpp3
-rw-r--r--src/mongo/db/scanandorder.h2
-rw-r--r--src/mongo/dbtests/namespacetests.cpp189
-rw-r--r--src/mongo/s/d_split.cpp13
34 files changed, 390 insertions, 422 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index a7873303039..e3ea7d89dc3 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -431,6 +431,7 @@ serverOnlyFiles = [ "db/curop.cpp",
"db/prefetch.cpp",
"db/repl/write_concern.cpp",
"db/btreecursor.cpp",
+ "db/index_legacy.cpp",
"db/index_selection.cpp",
"db/index/2d_access_method.cpp",
"db/index/2d_index_cursor.cpp",
@@ -486,7 +487,6 @@ serverOnlyFiles = [ "db/curop.cpp",
"db/dbcommands.cpp",
"db/compact.cpp",
"db/dbcommands_admin.cpp",
- "db/indexkey.cpp",
# most commands are only for mongod
"db/commands/apply_ops.cpp",
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp
index 11a3939220c..38948b3e5de 100644
--- a/src/mongo/db/cloner.cpp
+++ b/src/mongo/db/cloner.cpp
@@ -297,7 +297,6 @@ namespace mongo {
}
extern bool inDBRepair;
- extern const int DefaultIndexVersionNumber; // from indexkey.cpp
void ensureIdIndexForNewNs(const char *ns);
bool Cloner::go(const char *masterHost, string& errmsg, const string& fromdb, bool logForRepl, bool slaveOk, bool useReplAuth, bool snapshot, bool mayYield, bool mayBeInterrupted, int *errCode) {
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index 1513796145b..ba655255002 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -33,6 +33,7 @@
#include "mongo/db/dbmessage.h"
#include "mongo/db/dbwebserver.h"
#include "mongo/db/dur.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/index_rebuilder.h"
#include "mongo/db/initialize_server_global_state.h"
#include "mongo/db/instance.h"
@@ -368,7 +369,7 @@ namespace mongo {
for ( ; cursor && cursor->ok(); cursor->advance()) {
const BSONObj index = cursor->current();
const BSONObj key = index.getObjectField("key");
- const string plugin = KeyPattern::findPluginName(key);
+ const string plugin = IndexNames::findPluginName(key);
if (IndexNames::existedBefore24(plugin))
continue;
diff --git a/src/mongo/db/index.cpp b/src/mongo/db/index.cpp
index 3a9c2b1fa9f..c71b2a34195 100644
--- a/src/mongo/db/index.cpp
+++ b/src/mongo/db/index.cpp
@@ -26,8 +26,8 @@
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/background.h"
#include "mongo/db/btree.h"
-#include "mongo/db/fts/fts_enabled.h"
-#include "mongo/db/fts/fts_spec.h"
+#include "mongo/db/index_legacy.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/index/index_cursor.h"
#include "mongo/db/index/index_descriptor.h"
@@ -40,6 +40,9 @@
namespace mongo {
+ // What's the default version of our indices?
+ const int DefaultIndexVersionNumber = 1;
+
int removeFromSysIndexes(const char *ns, const char *idxName) {
string system_indexes = cc().database()->name + ".system.indexes";
BSONObjBuilder b;
@@ -79,11 +82,6 @@ namespace mongo {
return -1;
}
- const IndexSpec& IndexDetails::getSpec() const {
- SimpleMutex::scoped_lock lk(NamespaceDetailsTransient::_qcMutex);
- return NamespaceDetailsTransient::get_inlock( info.obj()["ns"].valuestr() ).getIndexSpec( this );
- }
-
/* delete this index. does NOT clean up the system catalog
(system.indexes or system.namespaces) -- only NamespaceIndex.
*/
@@ -148,7 +146,7 @@ namespace mongo {
for ( ; cursor && cursor->ok(); cursor->advance()) {
const BSONObj index = cursor->current();
const BSONObj key = index.getObjectField("key");
- const string plugin = KeyPattern::findPluginName(key);
+ const string plugin = IndexNames::findPluginName(key);
if (IndexNames::existedBefore24(plugin))
continue;
@@ -245,7 +243,7 @@ namespace mongo {
return false;
}
- string pluginName = KeyPattern::findPluginName( key );
+ string pluginName = IndexNames::findPluginName( key );
if (pluginName.size()) {
uassert(16734, str::stream() << "Unknown index plugin '" << pluginName << "' "
<< "in index "<< key,
@@ -257,16 +255,7 @@ namespace mongo {
{
BSONObj o = io;
- if (IndexNames::TEXT == pluginName || IndexNames::TEXT_INTERNAL == pluginName) {
- StringData desc = cc().desc();
- if ( desc.find( "conn" ) == 0 ) {
- // this is to make sure we only complain for users
- // if you do get a text index created an a primary
- // want it to index on the secondary as well
- massert(16808, "text search not enabled", fts::isTextSearchEnabled() );
- }
- o = fts::FTSSpec::fixSpec(o);
- }
+ o = IndexLegacy::adjustIndexSpecObject(o);
BSONObjBuilder b;
int v = DefaultIndexVersionNumber;
if( !o["v"].eoo() ) {
@@ -300,19 +289,4 @@ namespace mongo {
return true;
}
-
- void IndexSpec::reset(const IndexDetails * details) {
- _details = details;
- reset(details->info);
- }
-
- void IndexSpec::reset(const BSONObj& _info) {
- info = _info;
- keyPattern = info["key"].embeddedObjectUserCheck();
- if ( keyPattern.objsize() == 0 ) {
- out() << info.toString() << endl;
- verify(false);
- }
- _init();
- }
}
diff --git a/src/mongo/db/index.h b/src/mongo/db/index.h
index 902f7afd72f..d9332c89b6f 100644
--- a/src/mongo/db/index.h
+++ b/src/mongo/db/index.h
@@ -23,7 +23,6 @@
#include <vector>
#include "mongo/db/diskloc.h"
-#include "mongo/db/indexkey.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/key.h"
#include "mongo/db/namespace.h"
@@ -160,8 +159,6 @@ namespace mongo {
*/
void kill_idx();
- const IndexSpec& getSpec() const;
-
string toString() const {
return info.obj().toString();
}
diff --git a/src/mongo/db/index/2d_index_cursor.cpp b/src/mongo/db/index/2d_index_cursor.cpp
index 48d7bf72c64..d5877585464 100644
--- a/src/mongo/db/index/2d_index_cursor.cpp
+++ b/src/mongo/db/index/2d_index_cursor.cpp
@@ -322,6 +322,7 @@ namespace mongo {
scoped_ptr<BtreeCursor> _cursor;
scoped_ptr<FieldRangeSet> _frs;
+ // TODO: Turn into a KeyPattern object when FieldRangeVector takes one.
BSONObj _keyPattern;
BSONObj key() { return _cursor->currKey(); }
diff --git a/src/mongo/db/index/btree_key_generator.cpp b/src/mongo/db/index/btree_key_generator.cpp
index b4ca76de792..0efdbd7e96a 100644
--- a/src/mongo/db/index/btree_key_generator.cpp
+++ b/src/mongo/db/index/btree_key_generator.cpp
@@ -18,8 +18,9 @@
#include "mongo/util/mongoutils/str.h"
namespace mongo {
- // XXX: sigh this shouldnt' be here OR in indexkey.h
- static const int ParallelArraysCode = 10088;
+
+ // Used in scanandorder.cpp to inforatively error when we try to sort keys with parallel arrays.
+ const int BtreeKeyGenerator::ParallelArraysCode = 10088;
BtreeKeyGenerator::BtreeKeyGenerator(vector<const char*> fieldNames, vector<BSONElement> fixed,
bool isSparse)
@@ -50,7 +51,7 @@ namespace mongo {
static void assertParallelArrays( const char *first, const char *second ) {
stringstream ss;
ss << "cannot index parallel arrays [" << first << "] [" << second << "]";
- uasserted( ParallelArraysCode , ss.str() );
+ uasserted( BtreeKeyGenerator::ParallelArraysCode , ss.str() );
}
BtreeKeyGeneratorV0::BtreeKeyGeneratorV0(vector<const char*> fieldNames,
diff --git a/src/mongo/db/index/btree_key_generator.h b/src/mongo/db/index/btree_key_generator.h
index da46e2ee816..985981d7c98 100644
--- a/src/mongo/db/index/btree_key_generator.h
+++ b/src/mongo/db/index/btree_key_generator.h
@@ -22,6 +22,10 @@
namespace mongo {
+ /**
+ * Internal class used by BtreeAccessMethod to generate keys for indexed documents.
+ * This class is meant to be kept under the index access layer.
+ */
class BtreeKeyGenerator {
public:
BtreeKeyGenerator(vector<const char*> fieldNames, vector<BSONElement> fixed, bool isSparse);
@@ -29,6 +33,8 @@ namespace mongo {
void getKeys(const BSONObj &obj, BSONObjSet *keys) const;
+ static const int ParallelArraysCode;
+
protected:
// These are used by the getKeysImpl(s) below.
vector<const char*> _fieldNames;
diff --git a/src/mongo/db/index/catalog_hack.h b/src/mongo/db/index/catalog_hack.h
index 2b306b75462..c75d6f5a6d6 100644
--- a/src/mongo/db/index/catalog_hack.h
+++ b/src/mongo/db/index/catalog_hack.h
@@ -26,7 +26,6 @@
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/index/s2_access_method.h"
#include "mongo/db/index_names.h"
-#include "mongo/db/keypattern.h"
#include "mongo/db/pdfile.h"
namespace mongo {
@@ -36,8 +35,15 @@ namespace mongo {
*/
class CatalogHack {
public:
+
+ /**
+ * Older versions of MongoDB treated unknown index plugins as ascending Btree indices.
+ * We need to replicate this behavior. We use the version of the on-disk database to hint
+ * to us whether or not a given index was created as an actual instance of a special index,
+ * or if it was just treated as an increasing Btree index.
+ */
static bool shouldOverridePlugin(const BSONObj& keyPattern) {
- string pluginName = KeyPattern::findPluginName(keyPattern);
+ string pluginName = IndexNames::findPluginName(keyPattern);
bool known = IndexNames::isKnownName(pluginName);
if (NULL == cc().database()) {
@@ -73,11 +79,16 @@ namespace mongo {
}
}
- static string findPluginName(const BSONObj& keyPattern) {
+ /**
+ * This differs from IndexNames::findPluginName in that returns the plugin name we *should*
+ * use, not the plugin name inside of the provided key pattern. To understand when these
+ * differ, see shouldOverridePlugin.
+ */
+ static string getAccessMethodName(const BSONObj& keyPattern) {
if (shouldOverridePlugin(keyPattern)) {
return "";
} else {
- return KeyPattern::findPluginName(keyPattern);
+ return IndexNames::findPluginName(keyPattern);
}
}
@@ -87,11 +98,8 @@ namespace mongo {
}
static BtreeBasedAccessMethod* getBtreeBasedIndex(IndexDescriptor* desc) {
- if (shouldOverridePlugin(desc->keyPattern())) {
- return new BtreeAccessMethod(desc);
- }
+ string type = getAccessMethodName(desc->keyPattern());
- string type = KeyPattern::findPluginName(desc->keyPattern());
if (IndexNames::HASHED == type) {
return new HashAccessMethod(desc);
} else if (IndexNames::GEO_2DSPHERE == type) {
@@ -112,11 +120,8 @@ namespace mongo {
}
static IndexAccessMethod* getIndex(IndexDescriptor* desc) {
- if (shouldOverridePlugin(desc->keyPattern())) {
- return new BtreeAccessMethod(desc);
- }
+ string type = getAccessMethodName(desc->keyPattern());
- string type = KeyPattern::findPluginName(desc->keyPattern());
if (IndexNames::HASHED == type) {
return new HashAccessMethod(desc);
} else if (IndexNames::GEO_2DSPHERE == type) {
diff --git a/src/mongo/db/index/emulated_cursor.h b/src/mongo/db/index/emulated_cursor.h
index e4f41631e98..ad3500f5afc 100644
--- a/src/mongo/db/index/emulated_cursor.h
+++ b/src/mongo/db/index/emulated_cursor.h
@@ -142,7 +142,7 @@ namespace mongo {
EmulatedCursor(IndexDescriptor* descriptor, IndexAccessMethod* indexAccessMethod,
const BSONObj& order, int numWanted, const BSONObj& keyPattern)
: _descriptor(descriptor), _indexAccessMethod(indexAccessMethod),
- _keyPattern(keyPattern), _pluginName(KeyPattern::findPluginName(keyPattern)) {
+ _keyPattern(keyPattern), _pluginName(IndexNames::findPluginName(keyPattern)) {
IndexCursor *cursor;
indexAccessMethod->newCursor(&cursor);
diff --git a/src/mongo/db/index/hash_access_method.cpp b/src/mongo/db/index/hash_access_method.cpp
index 13a966fecf0..5d6f671bea0 100644
--- a/src/mongo/db/index/hash_access_method.cpp
+++ b/src/mongo/db/index/hash_access_method.cpp
@@ -28,20 +28,6 @@ namespace mongo {
return BSONElementHasher::hash64(e, seed);
}
- BSONObj HashAccessMethod::getMissingField(const IndexDetails& details) {
- BSONObj infoObj = details.info.obj();
- int hashVersion = infoObj["hashVersion"].numberInt();
- HashSeed seed = infoObj["seed"].numberInt();
-
- // Explicit null valued fields and missing fields are both represented in hashed indexes
- // using the hash value of the null BSONElement. This is partly for historical reasons
- // (hash of null was used in the initial release of hashed indexes and changing would alter
- // the data format). Additionally, in certain places the hashed index code and the index
- // bound calculation code assume null and missing are indexed identically.
- BSONObj nullObj = BSON("" << BSONNULL);
- return BSON("" << makeSingleKey(nullObj.firstElement(), seed, hashVersion));
- }
-
HashAccessMethod::HashAccessMethod(IndexDescriptor* descriptor)
: BtreeBasedAccessMethod(descriptor) {
@@ -69,9 +55,6 @@ namespace mongo {
massert(16765, "error: no hashed index field",
firstElt.str().compare(HASHED_INDEX_TYPE_IDENTIFIER) == 0);
_hashedField = firstElt.fieldName();
-
- BSONObj nullObj = BSON("" << BSONNULL);
- _missingKey = BSON("" << makeSingleKey(nullObj.firstElement(), _seed, _hashVersion));
}
Status HashAccessMethod::newCursor(IndexCursor** out) {
@@ -80,16 +63,24 @@ namespace mongo {
}
void HashAccessMethod::getKeys(const BSONObj& obj, BSONObjSet* keys) {
- const char* cstr = _hashedField.c_str();
+ getKeysImpl(obj, _hashedField, _seed, _hashVersion, _descriptor->isSparse(), keys);
+ }
+
+ // static
+ void HashAccessMethod::getKeysImpl(const BSONObj& obj, const string& hashedField, HashSeed seed,
+ int hashVersion, bool isSparse, BSONObjSet* keys) {
+ const char* cstr = hashedField.c_str();
BSONElement fieldVal = obj.getFieldDottedOrArray(cstr);
uassert(16766, "Error: hashed indexes do not currently support array values",
fieldVal.type() != Array );
if (!fieldVal.eoo()) {
- BSONObj key = BSON( "" << makeSingleKey( fieldVal , _seed , _hashVersion ) );
- keys->insert( key );
- } else if (!_descriptor->isSparse()) {
- keys->insert( _missingKey.copy() );
+ BSONObj key = BSON( "" << makeSingleKey(fieldVal, seed, hashVersion));
+ keys->insert(key);
+ }
+ else if (!isSparse) {
+ BSONObj nullObj = BSON("" << BSONNULL);
+ keys->insert(BSON("" << makeSingleKey(nullObj.firstElement(), seed, hashVersion)));
}
}
diff --git a/src/mongo/db/index/hash_access_method.h b/src/mongo/db/index/hash_access_method.h
index 19060cf3f96..0777f645159 100644
--- a/src/mongo/db/index/hash_access_method.h
+++ b/src/mongo/db/index/hash_access_method.h
@@ -43,15 +43,18 @@ namespace mongo {
return Status::OK();
}
- // Our missing field is different than the default missing field, this needs to be
- // exposed in s/d_split.cpp. That's the only thing that calls this.
- static BSONObj getMissingField(const IndexDetails& details);
-
/**
* Hashing function used by both this class and the cursors we create.
+ * Exposed for testing and so mongo/db/index_legacy.cpp can use it.
*/
static long long int makeSingleKey(const BSONElement& e, HashSeed seed, int v);
+ /**
+ * Exposed externally for testing purposes.
+ */
+ static void getKeysImpl(const BSONObj& obj, const string& hashedField, HashSeed seed,
+ int hashVersion, bool isSparse, BSONObjSet* keys);
+
private:
virtual void getKeys(const BSONObj& obj, BSONObjSet* keys);
diff --git a/src/mongo/db/index_legacy.cpp b/src/mongo/db/index_legacy.cpp
new file mode 100644
index 00000000000..a47544af518
--- /dev/null
+++ b/src/mongo/db/index_legacy.cpp
@@ -0,0 +1,81 @@
+/**
+* Copyright (C) 2013 10gen 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/>.
+*/
+
+#include "mongo/db/index_legacy.h"
+
+#include "mongo/db/client.h"
+#include "mongo/db/fts/fts_enabled.h"
+#include "mongo/db/fts/fts_spec.h"
+#include "mongo/db/index_names.h"
+#include "mongo/db/index/catalog_hack.h"
+#include "mongo/db/index/hash_access_method.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/namespace_details.h"
+
+namespace mongo {
+
+ // static
+ BSONObj IndexLegacy::adjustIndexSpecObject(const BSONObj& obj) {
+ string pluginName = IndexNames::findPluginName(obj.getObjectField("key"));
+
+ if (IndexNames::TEXT == pluginName || IndexNames::TEXT_INTERNAL == pluginName) {
+ StringData desc = cc().desc();
+ if (desc.find("conn") == 0) {
+ // this is to make sure we only complain for users
+ // if you do get a text index created an a primary
+ // want it to index on the secondary as well
+ massert(16811, "text search not enabled", fts::isTextSearchEnabled() );
+ }
+ return fts::FTSSpec::fixSpec(obj);
+ }
+
+ return obj;
+ }
+
+ // static
+ BSONObj IndexLegacy::getMissingField(const BSONObj& infoObj) {
+ if (IndexNames::HASHED == CatalogHack::getAccessMethodName(infoObj.getObjectField("key"))) {
+ int hashVersion = infoObj["hashVersion"].numberInt();
+ HashSeed seed = infoObj["seed"].numberInt();
+
+ // Explicit null valued fields and missing fields are both represented in hashed indexes
+ // using the hash value of the null BSONElement. This is partly for historical reasons
+ // (hash of null was used in the initial release of hashed indexes and changing would
+ // alter the data format). Additionally, in certain places the hashed index code and
+ // the index bound calculation code assume null and missing are indexed identically.
+ BSONObj nullObj = BSON("" << BSONNULL);
+ return BSON("" << HashAccessMethod::makeSingleKey(nullObj.firstElement(), seed,
+ hashVersion));
+ }
+ else {
+ BSONObjBuilder b;
+ b.appendNull("");
+ return b.obj();
+ }
+ }
+
+ // static
+ void IndexLegacy::postBuildHook(NamespaceDetails* tableToIndex, const IndexDetails& idx) {
+ // If it's an FTS index, we want to set the power of 2 flag.
+ string pluginName = CatalogHack::getAccessMethodName(idx.keyPattern());
+ if (IndexNames::TEXT == pluginName || IndexNames::TEXT_INTERNAL == pluginName) {
+ if (tableToIndex->setUserFlag(NamespaceDetails::Flag_UsePowerOf2Sizes)) {
+ tableToIndex->syncUserFlags(idx.parentNS());
+ }
+ }
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/index_legacy.h b/src/mongo/db/index_legacy.h
new file mode 100644
index 00000000000..ffa880c929f
--- /dev/null
+++ b/src/mongo/db/index_legacy.h
@@ -0,0 +1,67 @@
+
+/**
+* Copyright (C) 2013 10gen 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/>.
+*/
+
+#pragma once
+
+#include "mongo/db/jsobj.h"
+
+namespace mongo {
+
+ class IndexDetails;
+ class NamespaceDetails;
+
+ /**
+ * There has been some behavior concerning indexed access patterns -- both pre and post-index
+ * construction -- that does not quite fit in the access pattern model implemented in
+ * index/index_access_pattern.h. Such behavior can't be changed in the current implementation of
+ * the code.
+ *
+ * We grouped such exception/legacy behavior here.
+ */
+ class IndexLegacy {
+ public:
+ /**
+ * Adjust the provided index spec BSONObj depending on the type of index obj describes.
+ *
+ * This is a no-op unless the object describes a FTS index. To see what FTS does, look in
+ * FTSSpec::fixSpec in fts/fts_spec.cpp.
+ */
+ static BSONObj adjustIndexSpecObject(const BSONObj& obj);
+
+ /**
+ * Returns the BSONObj that is inserted into an index when the object is missing the keys
+ * the index is over.
+ *
+ * For every index *except hash*, this is the BSON equivalent of jstNULL.
+ * For the hash index, it's the hash of BSON("" << BSONNULL).
+ *
+ * s/d_split.cpp needs to know this.
+ *
+ * This is a significant leak of index functionality out of the index layer.
+ */
+ static BSONObj getMissingField(const BSONObj& infoObj);
+
+ /**
+ * Perform any post-build steps for this index.
+ *
+ * This is a no-op unless the index is a FTS index. In that case, we set the flag for using
+ * power of 2 sizes for space allocation.
+ */
+ static void postBuildHook(NamespaceDetails* tableToIndex, const IndexDetails& idx);
+ };
+
+} // namespace mongo
diff --git a/src/mongo/db/index_names.cpp b/src/mongo/db/index_names.cpp
index 6a9aac30bc3..873f11c0f41 100644
--- a/src/mongo/db/index_names.cpp
+++ b/src/mongo/db/index_names.cpp
@@ -16,6 +16,8 @@
#include "mongo/db/index_names.h"
+#include "mongo/db/jsobj.h"
+
namespace mongo {
const string IndexNames::GEO_2D = "2d";
const string IndexNames::GEO_HAYSTACK = "geoHaystack";
@@ -23,4 +25,18 @@ namespace mongo {
const string IndexNames::TEXT = "text";
const string IndexNames::TEXT_INTERNAL = "_fts";
const string IndexNames::HASHED = "hashed";
+
+ // static
+ string IndexNames::findPluginName(const BSONObj& keyPattern) {
+ BSONObjIterator i(keyPattern);
+
+ while (i.more()) {
+ BSONElement e = i.next();
+ if (String != e.type()) { continue; }
+ return e.String();
+ }
+
+ return "";
+ }
+
} // namespace mongo
diff --git a/src/mongo/db/index_names.h b/src/mongo/db/index_names.h
index c2eef144ad9..6b4cb8570d3 100644
--- a/src/mongo/db/index_names.h
+++ b/src/mongo/db/index_names.h
@@ -22,6 +22,8 @@ namespace mongo {
using std::string;
+ class BSONObj;
+
/**
* We use the string representation of index names all over the place, so we declare them all
* once here.
@@ -47,6 +49,12 @@ namespace mongo {
|| name == IndexNames::HASHED;
}
+ /**
+ * Return the first string value in the provided object. For an index key pattern,
+ * a field with a non-string value indicates a "special" (not straight Btree) index.
+ */
+ static string findPluginName(const BSONObj& keyPattern);
+
static bool isKnownName(const string& name) {
return name.empty()
|| name == IndexNames::GEO_2D
diff --git a/src/mongo/db/index_selection.cpp b/src/mongo/db/index_selection.cpp
index 431d51f8e0a..523106d25cf 100644
--- a/src/mongo/db/index_selection.cpp
+++ b/src/mongo/db/index_selection.cpp
@@ -28,9 +28,10 @@ namespace mongo {
const FieldRangeSet& queryConstraints,
const BSONObj& order) {
- string type = CatalogHack::findPluginName(keyPattern);
+ string type = CatalogHack::getAccessMethodName(keyPattern);
BSONObj query = queryConstraints.originalQuery();
+ // "" means it's a b-tree index, ascending or descending.
if ("" == type) {
// This is a quick first pass to determine the suitability of the index. It produces
// some false positives (returns HELPFUL for some indexes which are not particularly).
diff --git a/src/mongo/db/index_selection.h b/src/mongo/db/index_selection.h
index e64978f638e..bc8c999da3d 100644
--- a/src/mongo/db/index_selection.h
+++ b/src/mongo/db/index_selection.h
@@ -16,13 +16,13 @@
#pragma once
-#include "mongo/db/indexkey.h" // for IndexSuitability
-
namespace mongo {
class BSONObj;
class FieldRangeSet;
+ enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 };
+
/**
* This class is part of query optimization. For a given index (as uniquely described by
* keyPattern) and a given query (queryConstraints) and given sort order (order), return how
diff --git a/src/mongo/db/indexkey.cpp b/src/mongo/db/indexkey.cpp
deleted file mode 100644
index 56de9511ec7..00000000000
--- a/src/mongo/db/indexkey.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-// index_key.cpp
-
-/**
-* Copyright (C) 2008 10gen 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/>.
-*/
-
-#include "pch.h"
-#include "namespace-inl.h"
-#include "index.h"
-#include "background.h"
-#include "../util/stringutils.h"
-#include "mongo/util/mongoutils/str.h"
-#include "../util/text.h"
-#include "mongo/db/client.h"
-#include "mongo/db/database.h"
-#include "mongo/db/index/catalog_hack.h"
-#include "mongo/db/pdfile.h"
-#include "mongo/db/queryutil.h"
-
-namespace mongo {
-
- /** old (<= v1.8) : 0
- 1 is new version
- */
- const int DefaultIndexVersionNumber = 1;
-
- void IndexSpec::_init() {
- verify( keyPattern.objsize() );
-
- // some basics
- _nFields = keyPattern.nFields();
- _sparse = info["sparse"].trueValue();
- uassert( 13529 , "sparse only works for single field keys" , ! _sparse || _nFields );
-
-
- {
- // build _nullKey
-
- BSONObjBuilder b;
- BSONObjIterator i( keyPattern );
-
- while( i.more() ) {
- BSONElement e = i.next();
- _fieldNames.push_back( e.fieldName() );
- _fixed.push_back( BSONElement() );
- b.appendNull( "" );
- }
- _nullKey = b.obj();
- }
-
- {
- // _nullElt
- BSONObjBuilder b;
- b.appendNull( "" );
- _nullObj = b.obj();
- _nullElt = _nullObj.firstElement();
- }
-
- {
- // _undefinedElt
- BSONObjBuilder b;
- b.appendUndefined( "" );
- _undefinedObj = b.obj();
- _undefinedElt = _undefinedObj.firstElement();
- }
-
- _finishedInit = true;
- }
-
- string IndexSpec::getTypeName() const {
- return CatalogHack::findPluginName(_details->keyPattern());
- }
-
- string IndexSpec::toString() const {
- stringstream s;
- s << "IndexSpec @ " << hex << this << dec << ", "
- << "Details @ " << hex << _details << dec << ", "
- << "Type: " << getTypeName() << ", "
- << "nFields: " << _nFields << ", "
- << "KeyPattern: " << keyPattern << ", "
- << "Info: " << info;
- return s.str();
- }
-
- int IndexSpec::indexVersion() const {
- if ( !info.hasField( "v" ) ) {
- return DefaultIndexVersionNumber;
- }
- return IndexDetails::versionForIndexObj( info );
- }
-
-}
diff --git a/src/mongo/db/indexkey.h b/src/mongo/db/indexkey.h
deleted file mode 100644
index 7fed236db7e..00000000000
--- a/src/mongo/db/indexkey.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// index_key.h
-
-/**
-* Copyright (C) 2008 10gen 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/>.
-*/
-
-#pragma once
-
-#include <map>
-
-#include "mongo/db/diskloc.h"
-#include "mongo/db/index_names.h"
-#include "mongo/db/keypattern.h"
-#include "mongo/db/jsobj.h"
-
-namespace mongo {
-
- extern const int DefaultIndexVersionNumber;
-
- const int ParallelArraysCode = 10088;
-
- class Cursor;
- class IndexSpec;
- class IndexDetails;
- class FieldRangeSet;
-
- enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 };
-
- /* precomputed details about an index, used for inserting keys on updates
- stored/cached in NamespaceDetailsTransient, or can be used standalone
- */
- class IndexSpec {
- public:
- BSONObj keyPattern; // e.g., { name : 1 }
- BSONObj info; // this is the same as IndexDetails::info.obj()
-
- IndexSpec()
- : _details(0) , _finishedInit(false) {
- }
-
- explicit IndexSpec(const BSONObj& k, const BSONObj& m=BSONObj())
- : keyPattern(k) , info(m) , _details(0) , _finishedInit(false) {
- _init();
- }
-
- /**
- this is a DiscLoc of an IndexDetails info
- should have a key field
- */
- explicit IndexSpec(const DiskLoc& loc) {
- reset(loc);
- }
-
- void reset(const BSONObj& info);
- void reset(const IndexDetails * details); // determines rules based on pdfile version
- void reset(const DiskLoc& infoLoc) {
- reset(infoLoc.obj());
- }
-
- string getTypeName() const;
-
- const IndexDetails * getDetails() const {
- return _details;
- }
-
- bool isSparse() const { return _sparse; }
-
- string toString() const;
-
- protected:
-
- int indexVersion() const;
-
- BSONSizeTracker _sizeTracker;
- vector<const char*> _fieldNames;
- vector<BSONElement> _fixed;
-
- BSONObj _nullKey; // a full key with all fields null
- BSONObj _nullObj; // only used for _nullElt
- BSONElement _nullElt; // jstNull
-
- BSONObj _undefinedObj; // only used for _undefinedElt
- BSONElement _undefinedElt; // undefined
-
- int _nFields; // number of fields in the index
- bool _sparse; // if the index is sparse
- const IndexDetails * _details;
-
- void _init();
-
- friend class KeyGeneratorV0;
- friend class KeyGeneratorV1;
- public:
- bool _finishedInit;
- };
-
-
-} // namespace mongo
diff --git a/src/mongo/db/keypattern.cpp b/src/mongo/db/keypattern.cpp
index 6c1bb6d67e6..03a29c4dc2c 100644
--- a/src/mongo/db/keypattern.cpp
+++ b/src/mongo/db/keypattern.cpp
@@ -51,18 +51,6 @@ namespace mongo {
&& i.next().eoo();
}
- string KeyPattern::findPluginName(const BSONObj& keyPattern) {
- BSONObjIterator i(keyPattern);
-
- while (i.more()) {
- BSONElement e = i.next();
- if (String != e.type()) { continue; }
- return e.String();
- }
-
- return "";
- }
-
BSONObj KeyPattern::extractSingleKey(const BSONObj& doc ) const {
if ( _pattern.isEmpty() )
return BSONObj();
diff --git a/src/mongo/db/keypattern.h b/src/mongo/db/keypattern.h
index da206e10b72..c499bae4d69 100644
--- a/src/mongo/db/keypattern.h
+++ b/src/mongo/db/keypattern.h
@@ -86,12 +86,6 @@ namespace mongo {
*/
static bool isIdKeyPattern(const BSONObj& pattern);
- /**
- * Return the first string value in the provided object. For an index key pattern,
- * a field with a non-string value indicates a "special" (not straight Btree) index.
- */
- static string findPluginName(const BSONObj& keyPattern);
-
/* Takes a BSONObj whose field names are a prefix of the fields in this keyPattern, and
* outputs a new bound with MinKey values appended to match the fields in this keyPattern
* (or MaxKey values for descending -1 fields). This is useful in sharding for
diff --git a/src/mongo/db/namespace_details.cpp b/src/mongo/db/namespace_details.cpp
index 2be3d0d59c5..e5da0d6feb6 100644
--- a/src/mongo/db/namespace_details.cpp
+++ b/src/mongo/db/namespace_details.cpp
@@ -681,14 +681,12 @@ namespace mongo {
/* ------------------------------------------------------------------------- */
SimpleMutex NamespaceDetailsTransient::_qcMutex("qc");
- SimpleMutex NamespaceDetailsTransient::_isMutex("is");
NamespaceDetailsTransient::DMap NamespaceDetailsTransient::_nsdMap;
void NamespaceDetailsTransient::reset() {
Lock::assertWriteLocked(_ns);
clearQueryCache();
_keysComputed = false;
- _indexSpecs.clear();
}
NamespaceDetailsTransient::CMap& NamespaceDetailsTransient::get_cmap_inlock(const string& ns) {
diff --git a/src/mongo/db/namespace_details.h b/src/mongo/db/namespace_details.h
index e53d3afec9f..2401afa6707 100644
--- a/src/mongo/db/namespace_details.h
+++ b/src/mongo/db/namespace_details.h
@@ -20,6 +20,7 @@
#include "mongo/db/d_concurrency.h"
#include "mongo/db/diskloc.h"
#include "mongo/db/index.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/index_set.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/mongommf.h"
@@ -296,7 +297,7 @@ namespace mongo {
void findIndexByType( const string& name , vector<int>& matches ) {
IndexIterator i = ii();
while ( i.more() ) {
- if ( i.next().getSpec().getTypeName() == name )
+ if ( IndexNames::findPluginName(i.next().keyPattern()) == name )
matches.push_back( i.pos() - 1 );
}
}
@@ -496,23 +497,6 @@ namespace mongo {
return _indexedPaths;
}
- /* IndexSpec caching */
- private:
- map<const IndexDetails*,IndexSpec> _indexSpecs;
- static SimpleMutex _isMutex;
- public:
- const IndexSpec& getIndexSpec( const IndexDetails * details ) {
- IndexSpec& spec = _indexSpecs[details];
- if ( ! spec._finishedInit ) {
- SimpleMutex::scoped_lock lk(_isMutex);
- if ( ! spec._finishedInit ) {
- spec.reset( details );
- verify( spec._finishedInit );
- }
- }
- return spec;
- }
-
/* query cache (for query optimizer) ------------------------------------- */
private:
int _qcWriteCount;
diff --git a/src/mongo/db/pdfile.cpp b/src/mongo/db/pdfile.cpp
index d592991a014..8331fc87006 100644
--- a/src/mongo/db/pdfile.cpp
+++ b/src/mongo/db/pdfile.cpp
@@ -45,6 +45,7 @@ _ disallow system* manipulations from the database.
#include "mongo/db/db.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/extsort.h"
+#include "mongo/db/index_legacy.h"
#include "mongo/db/index_names.h"
#include "mongo/db/index_update.h"
#include "mongo/db/index/catalog_hack.h"
@@ -1531,13 +1532,7 @@ namespace mongo {
tableToIndex->addIndex(tabletoidxns.c_str());
getDur().writingInt(tableToIndex->indexBuildsInProgress) -= 1;
- // If it's an FTS index, we want to set the power of 2 flag.
- string pluginName = KeyPattern::findPluginName(idx.keyPattern());
- if (IndexNames::TEXT == pluginName || IndexNames::TEXT_INTERNAL == pluginName) {
- if (tableToIndex->setUserFlag(NamespaceDetails::Flag_UsePowerOf2Sizes)) {
- tableToIndex->syncUserFlags(idx.parentNS());
- }
- }
+ IndexLegacy::postBuildHook(tableToIndex, idx);
}
catch (...) {
// Generally, this will be called as an exception from building the index bubbles up.
diff --git a/src/mongo/db/query_optimizer_internal.cpp b/src/mongo/db/query_optimizer_internal.cpp
index dcd7516b357..c94212c1deb 100644
--- a/src/mongo/db/query_optimizer_internal.cpp
+++ b/src/mongo/db/query_optimizer_internal.cpp
@@ -545,7 +545,7 @@ namespace mongo {
int j = i.pos();
IndexDetails& ii = i.next();
BSONObj keyPattern = ii.keyPattern();
- string pluginName = CatalogHack::findPluginName(keyPattern);
+ string pluginName = CatalogHack::getAccessMethodName(keyPattern);
if (special.has(pluginName) &&
(USELESS != IndexSelection::isSuitableFor(keyPattern,
_qps.frsp().frsForIndex(d, j), _qps.order()))) {
@@ -1497,8 +1497,7 @@ namespace mongo {
while( i.more() ) {
IndexDetails& ii = i.next();
if ( indexWorks( ii.keyPattern(), min.isEmpty() ? max : min, ret.first, ret.second ) ) {
- if ( ii.getSpec().getTypeName().empty()) {
- //if ( ii.getSpec().getType() == 0 ) {
+ if (CatalogHack::getAccessMethodName(ii.keyPattern()).empty()) {
id = &ii;
keyPattern = ii.keyPattern();
break;
diff --git a/src/mongo/db/query_plan.cpp b/src/mongo/db/query_plan.cpp
index 6bb157369a6..de388f458c4 100644
--- a/src/mongo/db/query_plan.cpp
+++ b/src/mongo/db/query_plan.cpp
@@ -116,10 +116,10 @@ namespace mongo {
// If the parsing or index indicates this is a special query, don't continue the processing
if (!_special.empty() ||
- ( ("" != CatalogHack::findPluginName(_descriptor->keyPattern())) && (USELESS !=
+ ( ("" != CatalogHack::getAccessMethodName(_descriptor->keyPattern())) && (USELESS !=
IndexSelection::isSuitableFor(_descriptor->keyPattern(), _frs, _order)))) {
- _specialIndexName = CatalogHack::findPluginName(_descriptor->keyPattern());
+ _specialIndexName = CatalogHack::getAccessMethodName(_descriptor->keyPattern());
if (_special.empty()) _special = _specialIndexName;
massert( 13040 , (string)"no type for special: " + _special , "" != _specialIndexName);
@@ -284,7 +284,7 @@ doneCheckOrder:
_direction >= 0 ? 1 : -1 ) );
}
- if ( !_index->getSpec().getTypeName().empty()) { //_index->getSpec().getType() ) {
+ if ( "" != CatalogHack::getAccessMethodName(_descriptor->keyPattern())) {
return shared_ptr<Cursor>( BtreeCursor::make( _d,
*_index,
_frv->startKey(),
diff --git a/src/mongo/db/query_plan.h b/src/mongo/db/query_plan.h
index 3c6350cc180..fb950eb9465 100644
--- a/src/mongo/db/query_plan.h
+++ b/src/mongo/db/query_plan.h
@@ -18,7 +18,6 @@
#include "mongo/db/diskloc.h"
#include "mongo/db/index/index_descriptor.h"
-#include "mongo/db/indexkey.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/matcher.h"
#include "mongo/db/projection.h"
diff --git a/src/mongo/db/queryutil.cpp b/src/mongo/db/queryutil.cpp
index 6ac3433caf4..899c03d73eb 100644
--- a/src/mongo/db/queryutil.cpp
+++ b/src/mongo/db/queryutil.cpp
@@ -1540,6 +1540,12 @@ namespace mongo {
bool ok = false;
BSONObjSet keys;
+
+ /**
+ * Key generation by design is behind the index interface. There is an exception here
+ * because $or uses key generation to dedup its results. When $or is fixed to not require
+ * this, key generation will be removed from here.
+ */
_keyGenerator->getKeys(obj, &keys);
// TODO The representation of matching keys could potentially be optimized
@@ -1564,6 +1570,7 @@ namespace mongo {
verify( _direction >= 0 );
BSONObjCmp oc(_keyPattern);
BSONObjSet keys(oc);
+ // See FieldRangeVector::matches for comment on key generation.
_keyGenerator->getKeys(obj, &keys);
for( BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i ) {
if ( matchesKey( *i ) ) {
diff --git a/src/mongo/db/queryutil.h b/src/mongo/db/queryutil.h
index c53082c06af..a1eaf78bcf8 100644
--- a/src/mongo/db/queryutil.h
+++ b/src/mongo/db/queryutil.h
@@ -16,7 +16,6 @@
#pragma once
#include "jsobj.h"
-#include "indexkey.h"
#include "mongo/db/index/btree_key_generator.h"
namespace mongo {
@@ -548,6 +547,7 @@ namespace mongo {
vector<const char*> _fieldNames;
vector<BSONElement> _fixed;
+ // See FieldRangeVector::matches for comment on key generation.
scoped_ptr<BtreeKeyGenerator> _keyGenerator;
};
diff --git a/src/mongo/db/scanandorder.cpp b/src/mongo/db/scanandorder.cpp
index d3ed2beffa2..d1eab6a7e87 100644
--- a/src/mongo/db/scanandorder.cpp
+++ b/src/mongo/db/scanandorder.cpp
@@ -22,6 +22,7 @@
#include "mongo/db/scanandorder.h"
+#include "mongo/db/index/btree_key_generator.h"
#include "mongo/db/matcher.h"
#include "mongo/db/parsed_query.h"
#include "mongo/util/mongoutils/str.h"
@@ -37,7 +38,7 @@ namespace mongo {
k = _order.getKeyFromObject(o);
}
catch (UserException &e) {
- if ( e.getCode() == ParallelArraysCode ) { // cannot get keys for parallel arrays
+ if ( e.getCode() == BtreeKeyGenerator::ParallelArraysCode) { // cannot get keys for parallel arrays
// fix lasterror text to be more accurate.
uasserted( 15925, "cannot sort with keys that are parallel arrays" );
}
diff --git a/src/mongo/db/scanandorder.h b/src/mongo/db/scanandorder.h
index 4bcfb4e44f9..7038a8dae28 100644
--- a/src/mongo/db/scanandorder.h
+++ b/src/mongo/db/scanandorder.h
@@ -20,7 +20,7 @@
#pragma once
-#include "mongo/db/indexkey.h"
+#include "mongo/db/diskloc.h"
#include "mongo/db/projection.h"
#include "mongo/db/queryutil.h"
diff --git a/src/mongo/dbtests/namespacetests.cpp b/src/mongo/dbtests/namespacetests.cpp
index 82fe647cd87..3c944ad03f6 100644
--- a/src/mongo/dbtests/namespacetests.cpp
+++ b/src/mongo/dbtests/namespacetests.cpp
@@ -23,6 +23,7 @@
#include "../db/db.h"
#include "../db/json.h"
+#include "mongo/db/index_legacy.h"
#include "mongo/db/index_selection.h"
#include "mongo/db/index/btree_key_generator.h"
#include "mongo/db/index/hash_access_method.h"
@@ -1091,8 +1092,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{$within:{$box:[[100,0],[120,100]]}}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
+ ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1102,8 +1103,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{$within:{$box:[[100,0],[120,100]]}}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "b" << "2d" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "b" << "2d" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1113,8 +1114,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{$near:[100,0]}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
+ ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1126,8 +1127,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{lat:4,lon:5}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1140,8 +1141,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{$gt:4,$lt:5}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1151,8 +1152,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:[1,1]}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1162,8 +1163,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:1}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1173,8 +1174,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1187,8 +1188,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{$and:[{a:{$near:[100,0]}}]}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1202,9 +1203,9 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$near:[100,0]},$or:[{b:1}]}" );
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
- IndexSpec spec( BSON( "a" << "2d" ) );
+ BSONObj spec( BSON( "a" << "2d" ) );
ASSERT_EQUALS( OPTIMAL,
- IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(), BSONObj() ) );
+ IndexSelection::isSuitableFor(spec, frsp->getSingleKeyFRS(), BSONObj() ) );
}
};
@@ -1219,8 +1220,8 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$geoIntersects:{$geometry:{type:'Point',"
"coordinates:[40,5]}}}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
+ ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1231,8 +1232,8 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$geoIntersects:{$geometry:{type:'Point',"
"coordinates:[40,5]}}}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "b" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "b" << "2dsphere" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1242,8 +1243,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{$near:[100,0]}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
+ ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1256,8 +1257,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{lat:4,lon:5}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1267,8 +1268,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{$gt:4,$lt:5}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1278,8 +1279,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:[1,1]}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1291,8 +1292,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:1}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1302,8 +1303,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1316,8 +1317,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{$and:[{a:{$near:[100,0]}}]}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1331,9 +1332,9 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$near:[100,0]},$or:[{b:1}]}" );
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
- IndexSpec spec( BSON( "a" << "2dsphere" ) );
+ BSONObj spec( BSON( "a" << "2dsphere" ) );
ASSERT_EQUALS( OPTIMAL,
- IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(), BSONObj() ) );
+ IndexSelection::isSuitableFor(spec, frsp->getSingleKeyFRS(), BSONObj() ) );
}
};
@@ -1347,8 +1348,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:5}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1358,8 +1359,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{$gt:4}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1369,8 +1370,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{a:{$in:[1,2]}}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1383,8 +1384,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{$and:[{a:5}]}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1397,8 +1398,8 @@ namespace NamespaceTests {
void run() {
BSONObj query = fromjson( "{$and:[{a:5},{b:5}]}" );
FieldRangeSet frs( "n/a", query, true, true );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frs, BSONObj() ) );
}
};
@@ -1412,8 +1413,8 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{$or:[{a:5}]}" );
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(),
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frsp->getSingleKeyFRS(),
BSONObj() ) );
}
};
@@ -1428,8 +1429,8 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{z:5,$or:[{a:5}]}" );
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(),
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frsp->getSingleKeyFRS(),
BSONObj() ) );
}
};
@@ -1444,8 +1445,8 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{$or:[{a:5},{b:5}]}" );
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(),
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frsp->getSingleKeyFRS(),
BSONObj() ) );
}
};
@@ -1460,8 +1461,8 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:5,$or:[{z:5}]}" );
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
- IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(),
+ BSONObj spec( BSON( "a" << "hashed" ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec, frsp->getSingleKeyFRS(),
BSONObj() ) );
}
};
@@ -1471,6 +1472,74 @@ namespace NamespaceTests {
// GeoHaystack does not implement its own suitability(). See SERVER-8645.
} // namespace IndexSpecSuitability
+
+ namespace MissingFieldTests {
+
+ /** A missing field is represented as null in a btree index. */
+ class BtreeIndexMissingField {
+ public:
+ void run() {
+ BSONObj spec( BSON("key" << BSON( "a" << 1 ) ));
+ ASSERT_EQUALS(jstNULL, IndexLegacy::getMissingField(spec).firstElement().type());
+ }
+ };
+
+ /** A missing field is represented as null in a 2d index. */
+ class TwoDIndexMissingField {
+ public:
+ void run() {
+ BSONObj spec( BSON("key" << BSON( "a" << "2d" ) ));
+ ASSERT_EQUALS(jstNULL, IndexLegacy::getMissingField(spec).firstElement().type());
+ }
+ };
+
+ /** A missing field is represented with the hash of null in a hashed index. */
+ class HashedIndexMissingField {
+ public:
+ void run() {
+ BSONObj spec( BSON("key" << BSON( "a" << "hashed" ) ));
+ BSONObj nullObj = BSON( "a" << BSONNULL );
+
+ // Call getKeys on the nullObj.
+ BSONObjSet nullFieldKeySet;
+ HashAccessMethod::getKeysImpl(nullObj, "a", 0, 0, false, &nullFieldKeySet);
+ BSONElement nullFieldFromKey = nullFieldKeySet.begin()->firstElement();
+
+ ASSERT_EQUALS( HashAccessMethod::makeSingleKey( nullObj.firstElement(), 0, 0 ),
+ nullFieldFromKey.Long() );
+
+ BSONObj missingField = IndexLegacy::getMissingField(spec);
+ ASSERT_EQUALS( NumberLong, missingField.firstElement().type() );
+ ASSERT_EQUALS( nullFieldFromKey, missingField.firstElement());
+ }
+ };
+
+ /**
+ * A missing field is represented with the hash of null in a hashed index. This hash value
+ * depends on the hash seed.
+ */
+ class HashedIndexMissingFieldAlternateSeed {
+ public:
+ void run() {
+ BSONObj spec( BSON("key" << BSON( "a" << "hashed" ) << "seed" << 0x5eed ));
+ BSONObj nullObj = BSON( "a" << BSONNULL );
+
+ BSONObjSet nullFieldKeySet;
+ HashAccessMethod::getKeysImpl(nullObj, "a", 0x5eed, 0, false, &nullFieldKeySet);
+ BSONElement nullFieldFromKey = nullFieldKeySet.begin()->firstElement();
+
+ ASSERT_EQUALS( HashAccessMethod::makeSingleKey( nullObj.firstElement(), 0x5eed, 0 ),
+ nullFieldFromKey.Long() );
+
+ // Ensure that getMissingField recognizes that the seed is different (and returns
+ // the right key).
+ BSONObj missingField = IndexLegacy::getMissingField(spec);
+ ASSERT_EQUALS( NumberLong, missingField.firstElement().type());
+ ASSERT_EQUALS( nullFieldFromKey, missingField.firstElement());
+ }
+ };
+
+ } // namespace MissingFieldTests
namespace NamespaceDetailsTests {
@@ -2370,6 +2439,10 @@ namespace NamespaceTests {
add< NamespaceDetailsTests::Size >();
add< NamespaceDetailsTests::SetIndexIsMultikey >();
add< NamespaceDetailsTransientTests::ClearQueryCache >();
+ add< MissingFieldTests::BtreeIndexMissingField >();
+ add< MissingFieldTests::TwoDIndexMissingField >();
+ add< MissingFieldTests::HashedIndexMissingField >();
+ add< MissingFieldTests::HashedIndexMissingFieldAlternateSeed >();
}
} myall;
} // namespace NamespaceTests
diff --git a/src/mongo/s/d_split.cpp b/src/mongo/s/d_split.cpp
index 98e4847e3fa..ba302515fbf 100644
--- a/src/mongo/s/d_split.cpp
+++ b/src/mongo/s/d_split.cpp
@@ -31,7 +31,7 @@
#include "mongo/db/btreecursor.h"
#include "mongo/db/clientcursor.h"
#include "mongo/db/commands.h"
-#include "mongo/db/index/hash_access_method.h"
+#include "mongo/db/index_legacy.h"
#include "mongo/db/instance.h"
#include "mongo/db/jsobj.h"
#include "mongo/s/chunk.h" // for static genID only
@@ -133,16 +133,9 @@ namespace mongo {
// Find the 'missingField' value used to represent a missing document field in a key of
// this index.
- // NOTE A local copy of 'missingField' is made because IndexSpec objects may be
+ // NOTE A local copy of 'missingField' is made because indices may be
// invalidated during a db lock yield.
- BSONObj missingFieldObj;
- if (IndexNames::HASHED == KeyPattern::findPluginName(kp.toBSON())) {
- missingFieldObj = HashAccessMethod::getMissingField(*idx);
- } else {
- BSONObjBuilder b;
- b.appendNull("");
- missingFieldObj = b.obj();
- }
+ BSONObj missingFieldObj = IndexLegacy::getMissingField(idx->info.obj());
BSONElement missingField = missingFieldObj.firstElement();
// for now, the only check is that all shard keys are filled