diff options
Diffstat (limited to 's/mr_shard.cpp')
| -rw-r--r-- | s/mr_shard.cpp | 312 |
1 files changed, 0 insertions, 312 deletions
diff --git a/s/mr_shard.cpp b/s/mr_shard.cpp deleted file mode 100644 index 93f49d1ce79..00000000000 --- a/s/mr_shard.cpp +++ /dev/null @@ -1,312 +0,0 @@ -// mr_shard.cpp - -/** - * - * 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 "../util/net/message.h" -#include "../db/dbmessage.h" -#include "../scripting/engine.h" - -#include "mr_shard.h" - -namespace mongo { - - namespace mr_shard { - - AtomicUInt Config::JOB_NUMBER; - - JSFunction::JSFunction( string type , const BSONElement& e ) { - _type = type; - _code = e._asCode(); - - if ( e.type() == CodeWScope ) - _wantedScope = e.codeWScopeObject(); - } - - void JSFunction::init( State * state ) { - _scope = state->scope(); - assert( _scope ); - _scope->init( &_wantedScope ); - - _func = _scope->createFunction( _code.c_str() ); - uassert( 14836 , str::stream() << "couldn't compile code for: " << _type , _func ); - - // install in JS scope so that it can be called in JS mode - _scope->setFunction(_type.c_str(), _code.c_str()); - } - - /** - * Applies the finalize function to a tuple obj (key, val) - * Returns tuple obj {_id: key, value: newval} - */ - BSONObj JSFinalizer::finalize( const BSONObj& o ) { - Scope * s = _func.scope(); - - Scope::NoDBAccess no = s->disableDBAccess( "can't access db inside finalize" ); - s->invokeSafe( _func.func() , &o, 0 ); - - // don't want to use o.objsize() to size b - // since there are many cases where the point of finalize - // is converting many fields to 1 - BSONObjBuilder b; - b.append( o.firstElement() ); - s->append( b , "value" , "return" ); - return b.obj(); - } - - void JSReducer::init( State * state ) { - _func.init( state ); - } - - /** - * Reduces a list of tuple objects (key, value) to a single tuple {"0": key, "1": value} - */ - BSONObj JSReducer::reduce( const BSONList& tuples ) { - if (tuples.size() <= 1) - return tuples[0]; - BSONObj key; - int endSizeEstimate = 16; - _reduce( tuples , key , endSizeEstimate ); - - BSONObjBuilder b(endSizeEstimate); - b.appendAs( key.firstElement() , "0" ); - _func.scope()->append( b , "1" , "return" ); - return b.obj(); - } - - /** - * Reduces a list of tuple object (key, value) to a single tuple {_id: key, value: val} - * Also applies a finalizer method if present. - */ - BSONObj JSReducer::finalReduce( const BSONList& tuples , Finalizer * finalizer ) { - - BSONObj res; - BSONObj key; - - if (tuples.size() == 1) { - // 1 obj, just use it - key = tuples[0]; - BSONObjBuilder b(key.objsize()); - BSONObjIterator it(key); - b.appendAs( it.next() , "_id" ); - b.appendAs( it.next() , "value" ); - res = b.obj(); - } - else { - // need to reduce - int endSizeEstimate = 16; - _reduce( tuples , key , endSizeEstimate ); - BSONObjBuilder b(endSizeEstimate); - b.appendAs( key.firstElement() , "_id" ); - _func.scope()->append( b , "value" , "return" ); - res = b.obj(); - } - - if ( finalizer ) { - res = finalizer->finalize( res ); - } - - return res; - } - - /** - * actually applies a reduce, to a list of tuples (key, value). - * After the call, tuples will hold a single tuple {"0": key, "1": value} - */ - void JSReducer::_reduce( const BSONList& tuples , BSONObj& key , int& endSizeEstimate ) { - int sizeEstimate = ( tuples.size() * tuples.begin()->getField( "value" ).size() ) + 128; - - // need to build the reduce args: ( key, [values] ) - BSONObjBuilder reduceArgs( sizeEstimate ); - boost::scoped_ptr<BSONArrayBuilder> valueBuilder; - int sizeSoFar = 0; - unsigned n = 0; - for ( ; n<tuples.size(); n++ ) { - BSONObjIterator j(tuples[n]); - BSONElement keyE = j.next(); - if ( n == 0 ) { - reduceArgs.append( keyE ); - key = keyE.wrap(); - sizeSoFar = 5 + keyE.size(); - valueBuilder.reset(new BSONArrayBuilder( reduceArgs.subarrayStart( "tuples" ) )); - } - - BSONElement ee = j.next(); - - uassert( 14837 , "value too large to reduce" , ee.size() < ( BSONObjMaxUserSize / 2 ) ); - - if ( sizeSoFar + ee.size() > BSONObjMaxUserSize ) { - assert( n > 1 ); // if not, inf. loop - break; - } - - valueBuilder->append( ee ); - sizeSoFar += ee.size(); - } - assert(valueBuilder); - valueBuilder->done(); - BSONObj args = reduceArgs.obj(); - - Scope * s = _func.scope(); - - s->invokeSafe( _func.func() , &args, 0 ); - ++numReduces; - - if ( s->type( "return" ) == Array ) { - uasserted( 14838 , "reduce -> multiple not supported yet"); - return; - } - - endSizeEstimate = key.objsize() + ( args.objsize() / tuples.size() ); - - if ( n == tuples.size() ) - return; - - // the input list was too large, add the rest of elmts to new tuples and reduce again - // note: would be better to use loop instead of recursion to avoid stack overflow - BSONList x; - for ( ; n < tuples.size(); n++ ) { - x.push_back( tuples[n] ); - } - BSONObjBuilder temp( endSizeEstimate ); - temp.append( key.firstElement() ); - s->append( temp , "1" , "return" ); - x.push_back( temp.obj() ); - _reduce( x , key , endSizeEstimate ); - } - - Config::Config( const string& _dbname , const BSONObj& cmdObj ) { - - dbname = _dbname; - ns = dbname + "." + cmdObj.firstElement().valuestr(); - - verbose = cmdObj["verbose"].trueValue(); - jsMode = cmdObj["jsMode"].trueValue(); - - jsMaxKeys = 500000; - reduceTriggerRatio = 2.0; - maxInMemSize = 5 * 1024 * 1024; - - uassert( 14841 , "outType is no longer a valid option" , cmdObj["outType"].eoo() ); - - if ( cmdObj["out"].type() == String ) { - finalShort = cmdObj["out"].String(); - outType = REPLACE; - } - else if ( cmdObj["out"].type() == Object ) { - BSONObj o = cmdObj["out"].embeddedObject(); - - BSONElement e = o.firstElement(); - string t = e.fieldName(); - - if ( t == "normal" || t == "replace" ) { - outType = REPLACE; - finalShort = e.String(); - } - else if ( t == "merge" ) { - outType = MERGE; - finalShort = e.String(); - } - else if ( t == "reduce" ) { - outType = REDUCE; - finalShort = e.String(); - } - else if ( t == "inline" ) { - outType = INMEMORY; - } - else { - uasserted( 14839 , str::stream() << "unknown out specifier [" << t << "]" ); - } - - if (o.hasElement("db")) { - outDB = o["db"].String(); - } - } - else { - uasserted( 14840 , "'out' has to be a string or an object" ); - } - - if ( outType != INMEMORY ) { // setup names - tempLong = str::stream() << (outDB.empty() ? dbname : outDB) << ".tmp.mr." << cmdObj.firstElement().String() << "_" << finalShort << "_" << JOB_NUMBER++; - - incLong = tempLong + "_inc"; - - finalLong = str::stream() << (outDB.empty() ? dbname : outDB) << "." << finalShort; - } - - { - // scope and code - - if ( cmdObj["scope"].type() == Object ) - scopeSetup = cmdObj["scope"].embeddedObjectUserCheck(); - - reducer.reset( new JSReducer( cmdObj["reduce"] ) ); - if ( cmdObj["finalize"].type() && cmdObj["finalize"].trueValue() ) - finalizer.reset( new JSFinalizer( cmdObj["finalize"] ) ); - - } - - { - // query options - if ( cmdObj["limit"].isNumber() ) - limit = cmdObj["limit"].numberLong(); - else - limit = 0; - } - } - - State::State( const Config& c ) : _config( c ) { - _onDisk = _config.outType != Config::INMEMORY; - } - - State::~State() { - if ( _onDisk ) { - try { -// _db.dropCollection( _config.tempLong ); -// _db.dropCollection( _config.incLong ); - } - catch ( std::exception& e ) { - error() << "couldn't cleanup after map reduce: " << e.what() << endl; - } - } - - if (_scope) { - // cleanup js objects - ScriptingFunction cleanup = _scope->createFunction("delete _emitCt; delete _keyCt; delete _mrMap;"); - _scope->invoke(cleanup, 0, 0, 0, true); - } - } - - /** - * Initialize the mapreduce operation, creating the inc collection - */ - void State::init() { - // setup js - _scope.reset(globalScriptEngine->getPooledScope( _config.dbname ).release() ); -// _scope->localConnect( _config.dbname.c_str() ); - _scope->externalSetup(); - - if ( ! _config.scopeSetup.isEmpty() ) - _scope->init( &_config.scopeSetup ); - - _config.reducer->init( this ); - if ( _config.finalizer ) - _config.finalizer->init( this ); - _scope->setBoolean("_doFinal", _config.finalizer); - } - } -} - |
