Skip to content

Commit cf0eb2b

Browse files
committed
CXX-450 support the new listIndexes command format
1 parent 7060708 commit cf0eb2b

File tree

3 files changed

+98
-47
lines changed

3 files changed

+98
-47
lines changed

src/mongo/client/dbclient.cpp

Lines changed: 67 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,62 +1978,85 @@ namespace mongo {
19781978
list<BSONObj> DBClientWithCommands::getIndexSpecs( const string &ns, int options ) {
19791979
list<BSONObj> specs;
19801980

1981-
{
1982-
// TODO: This implementation only reads the first batch of results from the
1983-
// listIndexes command, and masserts if there are multiple batches to read. A
1984-
// correct implementation needs to instantiate a command cursor from the command
1985-
// response object, and use it to read in all of the command results.
1986-
BSONObj cmd = BSON(
1987-
"listIndexes" << nsToCollectionSubstring( ns ) <<
1988-
"cursor" << BSONObj()
1989-
);
1990-
1991-
BSONObj res;
1992-
if ( runCommand( nsToDatabase( ns ), cmd, res, options ) ) {
1993-
BSONObj cursorObj = res["cursor"].Obj();
1994-
massert(28587, "reading multiple batches from listIndexes not implemented",
1995-
cursorObj["id"].numberInt() == 0);
1996-
BSONObjIterator i( cursorObj["firstBatch"].Obj() );
1997-
while ( i.more() ) {
1998-
specs.push_back( i.next().Obj().getOwned() );
1999-
}
2000-
return specs;
2001-
}
2002-
int code = res["code"].numberInt();
2003-
string errmsg = res["errmsg"].valuestrsafe();
2004-
if ( code == ErrorCodes::CommandNotFound ||
2005-
errmsg.find( "no such cmd" ) != string::npos ) {
2006-
// old version of server, ok, fall through to old code
2007-
}
2008-
else if ( code == ErrorCodes::NamespaceNotFound ) {
2009-
return specs;
2010-
}
2011-
else {
2012-
uasserted( 18631, str::stream() << "listIndexes failed: " << res );
1981+
auto_ptr<DBClientCursor> specs_cursor = enumerateIndexes(ns, options);
1982+
1983+
if ( specs_cursor.get() ) {
1984+
while ( specs_cursor->more() ) {
1985+
specs.push_back(specs_cursor->nextSafe().getOwned());
20131986
}
20141987
}
20151988

2016-
// fallback to querying system.indexes
2017-
// TODO(spencer): Remove fallback behavior after 2.8
2018-
auto_ptr<DBClientCursor> cursor = query(NamespaceString(ns).getSystemIndexesCollection(),
2019-
BSON("ns" << ns), 0, 0, 0, options);
2020-
while ( cursor->more() ) {
2021-
BSONObj spec = cursor->nextSafe();
2022-
specs.push_back( spec.getOwned() );
2023-
}
20241989
return specs;
20251990
}
20261991

2027-
list<std::string> DBClientWithCommands::getIndexNames( const std::string& ns ) {
1992+
list<std::string> DBClientWithCommands::getIndexNames( const std::string& ns, int options ) {
20281993
list<std::string> indexNames;
2029-
list<BSONObj> specs( getIndexSpecs(ns) );
20301994

2031-
for (list<BSONObj>::const_iterator it = specs.begin(); it != specs.end(); ++it) {
2032-
indexNames.push_back((*it)["name"].valuestr());
1995+
auto_ptr<DBClientCursor> specs_cursor = enumerateIndexes(ns, options);
1996+
1997+
if ( specs_cursor.get() ) {
1998+
while ( specs_cursor->more() ) {
1999+
indexNames.push_back(specs_cursor->nextSafe()["name"].valuestr());
2000+
}
20332001
}
2002+
20342003
return indexNames;
20352004
}
20362005

2006+
auto_ptr<DBClientCursor> DBClientWithCommands::enumerateIndexes( const string& ns, int options ) {
2007+
const NamespaceString nsstring(ns);
2008+
2009+
BSONObj cmd = BSON("listIndexes" << nsstring.coll() << "cursor" << BSONObj());
2010+
2011+
auto_ptr<DBClientCursor> cursor = this->query(nsstring.getCommandNS(), cmd, 1, 0, NULL,
2012+
options, 0);
2013+
BSONObj result = cursor->peekFirst();
2014+
2015+
if ( isOk(result) ) {
2016+
// Command worked -- we are on MongoDB 2.7.6 or above
2017+
DBClientCursorShim* cursor_shim;
2018+
2019+
// Select the appropriate shim for this version of MongoDB
2020+
if ( result.hasField("indexes") ) {
2021+
// MongoDB 2.7.6 to 2.8.0-rc2 behavior
2022+
cursor_shim = new DBClientCursorShimArray(*cursor, "indexes");
2023+
}
2024+
else {
2025+
// MongoDB 2.8.0-rc3+ behavior
2026+
cursor_shim = new DBClientCursorShimCursorID(*cursor);
2027+
static_cast<DBClientCursorShimCursorID*>(cursor_shim)->get_cursor();
2028+
}
2029+
2030+
// Insert the shim
2031+
cursor->shim.reset(cursor_shim);
2032+
}
2033+
else {
2034+
// Command failed -- we are either on an older MongoDB or something else happened
2035+
int error_code = result["code"].numberInt();
2036+
string errmsg = result["errmsg"].valuestrsafe();
2037+
2038+
if ( error_code == ErrorCodes::NamespaceNotFound ) {
2039+
cursor.reset(NULL);
2040+
}
2041+
else if (
2042+
( error_code == ErrorCodes::CommandNotFound ) ||
2043+
( error_code == 13390 ) ||
2044+
( errmsg.find( "no such cmd" ) != string::npos )
2045+
) {
2046+
// MongoDB < 2.7.6 behavior -- query system.indexes
2047+
cursor.reset(query(nsstring.getSystemIndexesCollection(), BSON("ns" << ns),
2048+
0, 0, 0, options).release());
2049+
}
2050+
else {
2051+
// Something else happened, uassert with the reason
2052+
uasserted( 18631, str::stream() << "listIndexes failed: " << result );
2053+
}
2054+
}
2055+
2056+
return cursor;
2057+
}
2058+
2059+
20372060
void DBClientWithCommands::dropIndex( const string& ns , BSONObj keys ) {
20382061
dropIndex( ns , genIndexName( keys ) );
20392062
}

src/mongo/client/dbclientinterface.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,8 +1144,8 @@ namespace mongo {
11441144
* }
11451145
* }
11461146
*/
1147-
std::auto_ptr<DBClientCursor> enumerateCollections ( const std::string& db,
1148-
const BSONObj& filter = BSONObj() );
1147+
std::auto_ptr<DBClientCursor> enumerateCollections( const std::string& db,
1148+
const BSONObj& filter = BSONObj() );
11491149

11501150
bool exists( const std::string& ns );
11511151

@@ -1177,7 +1177,9 @@ namespace mongo {
11771177
/**
11781178
* Enumerates all indexes on ns (a db-qualified collection name). Returns a list of the index names.
11791179
*/
1180-
virtual std::list<std::string> getIndexNames( const std::string& ns );
1180+
virtual std::list<std::string> getIndexNames( const std::string& ns, int options = 0 );
1181+
1182+
virtual std::auto_ptr<DBClientCursor> enumerateIndexes( const std::string& ns, int options = 0 );
11811183

11821184
virtual void dropIndex( const std::string& ns , BSONObj keys );
11831185
virtual void dropIndex( const std::string& ns , const std::string& indexName );

src/mongo/integration/standalone/dbclient_test.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,7 @@ namespace {
684684
}
685685

686686
TEST_F(DBClientTest, GetIndexNames) {
687+
ASSERT_TRUE(c.getIndexNames(TEST_DB + ".fake").empty());
687688
ASSERT_TRUE(c.getIndexNames(TEST_NS).empty());
688689

689690
c.insert(TEST_NS, BSON("test" << "random data"));
@@ -698,6 +699,31 @@ namespace {
698699
ASSERT_EQUALS("test_1", names.front());
699700
}
700701

702+
TEST_F(DBClientTest, GetIndexSpecs) {
703+
ASSERT_TRUE(c.getIndexSpecs(TEST_DB + ".fake").empty());
704+
ASSERT_TRUE(c.getIndexSpecs(TEST_NS).empty());
705+
706+
c.insert(TEST_NS, BSON("test" << "random data"));
707+
ASSERT_EQUALS(1U, c.getIndexSpecs(TEST_NS).size());
708+
709+
IndexSpec spec;
710+
spec.addKey("test", IndexSpec::kIndexTypeAscending);
711+
spec.unique(true);
712+
c.createIndex(TEST_NS, spec);
713+
714+
list<BSONObj> specs = c.getIndexSpecs(TEST_NS);
715+
716+
ASSERT_EQUALS(2U, specs.size());
717+
ASSERT_EQUALS("_id_", specs.front()["name"].String());
718+
ASSERT_EQUALS(BSON("_id" << 1), specs.front()["key"].Obj());
719+
ASSERT_EQUALS(TEST_NS, specs.front()["ns"].String());
720+
specs.pop_front();
721+
ASSERT_EQUALS("test_1", specs.front()["name"].String());
722+
ASSERT_EQUALS(BSON("test" << 1), specs.front()["key"].Obj());
723+
ASSERT_EQUALS(TEST_NS, specs.front()["ns"].String());
724+
ASSERT_TRUE(specs.front()["unique"].trueValue());
725+
}
726+
701727
TEST_F(DBClientTest, DropIndexes) {
702728
c.createIndex(TEST_NS, BSON("test" << 1));
703729
ASSERT_EQUALS(2U, c.getIndexNames(TEST_NS).size());

0 commit comments

Comments
 (0)