/* must call this on a delete so we clean up the cursors. */ void ClientCursor::aboutToDelete(const DiskLoc& dl) { recursive_scoped_lock lock(ccmutex); Database *db = cc().database(); assert(db); aboutToDeleteForSharding( db , dl ); CCByLoc& bl = db->ccByLoc; CCByLoc::iterator j = bl.lower_bound(dl); CCByLoc::iterator stop = bl.upper_bound(dl); if ( j == stop ) return; vector<ClientCursor*> toAdvance; while ( 1 ) { toAdvance.push_back(j->second); DEV assert( j->first == dl ); ++j; if ( j == stop ) break; } wassert( toAdvance.size() < 5000 ); for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ){ ClientCursor* cc = *i; wassert(cc->_db == db); if ( cc->_doingDeletes ) continue; Cursor *c = cc->c.get(); if ( c->capped() ){ delete cc; continue; } c->checkLocation(); DiskLoc tmp1 = c->refLoc(); if ( tmp1 != dl ) { /* this might indicate a failure to call ClientCursor::updateLocation() */ problem() << "warning: cursor loc " << tmp1 << " does not match byLoc position " << dl << " !" << endl; } c->advance(); if ( c->eof() ) { // advanced to end // leave ClientCursor in place so next getMore doesn't fail // still need to mark new location though cc->updateLocation(); } else { wassert( c->refLoc() != dl ); cc->updateLocation(); } } }
/* must call this on a delete so we clean up the cursors. */ void ClientCursor::aboutToDelete(const DiskLoc& dl) { recursive_scoped_lock lock(ccmutex); CCByLoc::iterator j = byLoc.lower_bound(dl); CCByLoc::iterator stop = byLoc.upper_bound(dl); if ( j == stop ) return; vector<ClientCursor*> toAdvance; while ( 1 ) { toAdvance.push_back(j->second); DEV assert( j->first == dl ); ++j; if ( j == stop ) break; } wassert( toAdvance.size() < 5000 ); for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ){ ClientCursor* cc = *i; if ( cc->_doingDeletes ) continue; Cursor *c = cc->c.get(); if ( c->capped() ){ delete cc; continue; } c->checkLocation(); DiskLoc tmp1 = c->refLoc(); if ( tmp1 != dl ) { /* this might indicate a failure to call ClientCursor::updateLocation() */ problem() << "warning: cursor loc " << tmp1 << " does not match byLoc position " << dl << " !" << endl; } c->advance(); if ( c->eof() ) { // advanced to end -- delete cursor delete cc; } else { wassert( c->refLoc() != dl ); cc->updateLocation(); } } }
bool ODBCDriver::populateROWID(ODBCConnection* connection ) { // pass true, as we want *some* table. If there are no tables which already exist // lets at least get the kexidb system tables QStringList tableNames = connection->tableNames(true); if ( tableNames.size() == 0 ) { return false; } QString tableName = tableNames.first(); // get any existing table name // the ODBC function which retrieves special columns needs some table to work on // as we are inerested only in pseudo columns like ROWID, any table would do ODBCSpecialColumnsQueryUnit* queryUnit = new ODBCSpecialColumnsQueryUnit( connection , tableName ); Cursor* cursor = new ODBCCursor( connection, queryUnit ); if ( !cursor->open() || !cursor->moveFirst() ) { connection->deleteCursor( cursor ); return false; } // we need exactly one pseudo-column. So if the pseudo column count is greater than that, quit :( unsigned int pseudoColumnCount = 0; QString columnName; while ( !cursor->eof() ) { // eigth column is the pseudo column indicator ( cursor indexes by 0, hence we use 7 ) // see http://msdn.microsoft.com/en-us/library/ms714602(VS.85).aspx if ( cursor->value( 7 ).toInt() != ( int )SQL_PC_PSEUDO ) continue; // else we have a pseudo column ! columnName = cursor->value( 0 ).toString(); pseudoColumnCount++; } if ( pseudoColumnCount == 1 ) { beh->ROW_ID_FIELD_NAME = columnName; } return true; }
/* must call this on a delete so we clean up the cursors. */ void ClientCursor::aboutToDelete(const DiskLoc& dl) { NoPageFaultsAllowed npfa; recursive_scoped_lock lock(ccmutex); Database *db = cc().database(); verify(db); aboutToDeleteForSharding( db , dl ); CCByLoc& bl = db->ccByLoc; CCByLoc::iterator j = bl.lower_bound(ByLocKey::min(dl)); CCByLoc::iterator stop = bl.upper_bound(ByLocKey::max(dl)); if ( j == stop ) return; vector<ClientCursor*> toAdvance; while ( 1 ) { toAdvance.push_back(j->second); DEV verify( j->first.loc == dl ); ++j; if ( j == stop ) break; } if( toAdvance.size() >= 3000 ) { log() << "perf warning MPW101: " << toAdvance.size() << " cursors for one diskloc " << dl.toString() << ' ' << toAdvance[1000]->_ns << ' ' << toAdvance[2000]->_ns << ' ' << toAdvance[1000]->_pinValue << ' ' << toAdvance[2000]->_pinValue << ' ' << toAdvance[1000]->_pos << ' ' << toAdvance[2000]->_pos << ' ' << toAdvance[1000]->_idleAgeMillis << ' ' << toAdvance[2000]->_idleAgeMillis << ' ' << toAdvance[1000]->_doingDeletes << ' ' << toAdvance[2000]->_doingDeletes << endl; //wassert( toAdvance.size() < 5000 ); } for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ) { ClientCursor* cc = *i; wassert(cc->_db == db); if ( cc->_doingDeletes ) continue; Cursor *c = cc->_c.get(); if ( c->capped() ) { /* note we cannot advance here. if this condition occurs, writes to the oplog have "caught" the reader. skipping ahead, the reader would miss postentially important data. */ delete cc; continue; } c->recoverFromYield(); DiskLoc tmp1 = c->refLoc(); if ( tmp1 != dl ) { // This might indicate a failure to call ClientCursor::prepareToYield() but it can // also happen during correct operation, see SERVER-2009. problem() << "warning: cursor loc " << tmp1 << " does not match byLoc position " << dl << " !" << endl; } else { c->advance(); } while (!c->eof() && c->refLoc() == dl) { /* We don't delete at EOF because we want to return "no more results" rather than "no such cursor". * The loop is to handle MultiKey indexes where the deleted record is pointed to by multiple adjacent keys. * In that case we need to advance until we get to the next distinct record or EOF. * SERVER-4154 * SERVER-5198 * But see SERVER-5725. */ c->advance(); } cc->updateLocation(); } }
/* must call this on a delete so we clean up the cursors. */ void ClientCursor::aboutToDelete(const DiskLoc& dl) { recursive_scoped_lock lock(ccmutex); Database *db = cc().database(); assert(db); aboutToDeleteForSharding( db , dl ); CCByLoc& bl = db->ccByLoc; CCByLoc::iterator j = bl.lower_bound(ByLocKey::min(dl)); CCByLoc::iterator stop = bl.upper_bound(ByLocKey::max(dl)); if ( j == stop ) return; vector<ClientCursor*> toAdvance; while ( 1 ) { toAdvance.push_back(j->second); DEV assert( j->first.loc == dl ); ++j; if ( j == stop ) break; } if( toAdvance.size() >= 3000 ) { log() << "perf warning MPW101: " << toAdvance.size() << " cursors for one diskloc " << dl.toString() << ' ' << toAdvance[1000]->_ns << ' ' << toAdvance[2000]->_ns << ' ' << toAdvance[1000]->_pinValue << ' ' << toAdvance[2000]->_pinValue << ' ' << toAdvance[1000]->_pos << ' ' << toAdvance[2000]->_pos << ' ' << toAdvance[1000]->_idleAgeMillis << ' ' << toAdvance[2000]->_idleAgeMillis << ' ' << toAdvance[1000]->_doingDeletes << ' ' << toAdvance[2000]->_doingDeletes << endl; //wassert( toAdvance.size() < 5000 ); } for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ) { ClientCursor* cc = *i; wassert(cc->_db == db); if ( cc->_doingDeletes ) continue; Cursor *c = cc->_c.get(); if ( c->capped() ) { /* note we cannot advance here. if this condition occurs, writes to the oplog have "caught" the reader. skipping ahead, the reader would miss postentially important data. */ delete cc; continue; } c->checkLocation(); DiskLoc tmp1 = c->refLoc(); if ( tmp1 != dl ) { // This might indicate a failure to call ClientCursor::updateLocation() but it can // also happen during correct operation, see SERVER-2009. problem() << "warning: cursor loc " << tmp1 << " does not match byLoc position " << dl << " !" << endl; } else { c->advance(); } if ( c->eof() ) { // advanced to end // leave ClientCursor in place so next getMore doesn't fail // still need to mark new location though cc->updateLocation(); } else { wassert( c->refLoc() != dl ); cc->updateLocation(); } } }
/* must call this on a delete so we clean up the cursors. */ void ClientCursor::aboutToDelete(const StringData& ns, const NamespaceDetails* nsd, const DiskLoc& dl) { // Begin cursor-only NoPageFaultsAllowed npfa; // End cursor-only recursive_scoped_lock lock(ccmutex); Database *db = cc().database(); verify(db); aboutToDeleteForSharding( ns, db, nsd, dl ); // Check our non-cached active runner list. for (set<Runner*>::iterator it = nonCachedRunners.begin(); it != nonCachedRunners.end(); ++it) { Runner* runner = *it; if (0 == ns.compare(runner->ns())) { runner->invalidate(dl); } } // TODO: This requires optimization. We walk through *all* CCs and send the delete to every // CC open on the db we're deleting from. We could: // 1. Map from ns to open runners, // 2. Map from ns -> (a map of DiskLoc -> runners who care about that DL) // // We could also queue invalidations somehow and have them processed later in the runner's // read locks. for (CCById::const_iterator it = clientCursorsById.begin(); it != clientCursorsById.end(); ++it) { ClientCursor* cc = it->second; // We're only interested in cursors over one db. if (cc->_db != db) { continue; } if (NULL == cc->_runner.get()) { continue; } cc->_runner->invalidate(dl); } // Begin cursor-only. Only cursors that are in ccByLoc are processed here. CCByLoc& bl = db->ccByLoc(); CCByLoc::iterator j = bl.lower_bound(ByLocKey::min(dl)); CCByLoc::iterator stop = bl.upper_bound(ByLocKey::max(dl)); if ( j == stop ) return; vector<ClientCursor*> toAdvance; while ( 1 ) { toAdvance.push_back(j->second); DEV verify( j->first.loc == dl ); ++j; if ( j == stop ) break; } if( toAdvance.size() >= 3000 ) { log() << "perf warning MPW101: " << toAdvance.size() << " cursors for one diskloc " << dl.toString() << ' ' << toAdvance[1000]->_ns << ' ' << toAdvance[2000]->_ns << ' ' << toAdvance[1000]->_pinValue << ' ' << toAdvance[2000]->_pinValue << ' ' << toAdvance[1000]->_pos << ' ' << toAdvance[2000]->_pos << ' ' << toAdvance[1000]->_idleAgeMillis << ' ' << toAdvance[2000]->_idleAgeMillis << ' ' << toAdvance[1000]->_doingDeletes << ' ' << toAdvance[2000]->_doingDeletes << endl; //wassert( toAdvance.size() < 5000 ); } for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ) { ClientCursor* cc = *i; wassert(cc->_db == db); if ( cc->_doingDeletes ) continue; Cursor *c = cc->_c.get(); if ( c->capped() ) { /* note we cannot advance here. if this condition occurs, writes to the oplog have "caught" the reader. skipping ahead, the reader would miss postentially important data. */ delete cc; continue; } c->recoverFromYield(); DiskLoc tmp1 = c->refLoc(); if ( tmp1 != dl ) { // This might indicate a failure to call ClientCursor::prepareToYield() but it can // also happen during correct operation, see SERVER-2009. problem() << "warning: cursor loc " << tmp1 << " does not match byLoc position " << dl << " !" << endl; } else { c->advance(); } while (!c->eof() && c->refLoc() == dl) { /* We don't delete at EOF because we want to return "no more results" rather than "no such cursor". * The loop is to handle MultiKey indexes where the deleted record is pointed to by multiple adjacent keys. * In that case we need to advance until we get to the next distinct record or EOF. * SERVER-4154 * SERVER-5198 * But see SERVER-5725. */ c->advance(); } cc->updateLocation(); } // End cursor-only }
bool ODBCDriver::populateTypeInfo(ODBCConnection* connection ) { ODBCTypeInfoQueryUnit* queryUnit = new ODBCTypeInfoQueryUnit( connection ); Cursor* cursor = new ODBCCursor( connection, queryUnit ); if ( !cursor->open() || !cursor->moveFirst() ) { connection->deleteCursor( cursor ); return false; } while ( !cursor->eof() ) { // get all the values QString typeName = cursor->value( 0 ).toString(); switch( cursor->value(1 ).toInt() ) { case SQL_TINYINT: setTypeName(Field::Byte, typeName); break; case SQL_SMALLINT: setTypeName(Field::ShortInteger, typeName); break; case SQL_INTEGER: setTypeName(Field::Integer, typeName); break; case SQL_BIGINT: setTypeName(Field::BigInteger, typeName); break; case SQL_BIT: setTypeName(Field::Boolean, typeName); break; case SQL_TYPE_DATE: setTypeName(Field::Date, typeName); break; case SQL_TYPE_TIMESTAMP: setTypeName(Field::DateTime, typeName); break; case SQL_TYPE_TIME: setTypeName(Field::Time, typeName); break; case SQL_FLOAT: setTypeName(Field::Float, typeName); break; case SQL_DOUBLE: setTypeName(Field::Double, typeName); break; case SQL_VARCHAR: setTypeName(Field::Text, typeName); break; case SQL_LONGVARCHAR: setTypeName(Field::LongText, typeName); break; case SQL_VARBINARY: setTypeName(Field::BLOB, typeName); break; default: break; } if (!cursor->moveNext() && cursor->error()) { connection->deleteCursor(cursor); return false; } } return connection->deleteCursor( cursor ); }