DocumentSource::GetNextResult DocumentSourceCollStats::getNext() {
    pExpCtx->checkForInterrupt();

    if (_finished) {
        return GetNextResult::makeEOF();
    }

    _finished = true;

    BSONObjBuilder builder;

    builder.append("ns", pExpCtx->ns.ns());

    auto shardName = _mongod->getShardName(pExpCtx->opCtx);

    if (!shardName.empty()) {
        builder.append("shard", shardName);
    }

    builder.append("host", getHostNameCachedAndPort());
    builder.appendDate("localTime", jsTime());

    if (_collStatsSpec.hasField("latencyStats")) {
        // If the latencyStats field exists, it must have been validated as an object when parsing.
        bool includeHistograms = false;
        if (_collStatsSpec["latencyStats"].type() == BSONType::Object) {
            includeHistograms = _collStatsSpec["latencyStats"]["histograms"].boolean();
        }
        _mongod->appendLatencyStats(pExpCtx->ns, includeHistograms, &builder);
    }

    if (_collStatsSpec.hasField("storageStats")) {
        // If the storageStats field exists, it must have been validated as an object when parsing.
        BSONObjBuilder storageBuilder(builder.subobjStart("storageStats"));
        Status status = _mongod->appendStorageStats(
            pExpCtx->ns, _collStatsSpec["storageStats"].Obj(), &storageBuilder);
        storageBuilder.doneFast();
        if (!status.isOK()) {
            uasserted(40280,
                      str::stream() << "Unable to retrieve storageStats in $collStats stage: "
                                    << status.reason());
        }
    }

    if (_collStatsSpec.hasField("count")) {
        Status status = _mongod->appendRecordCount(pExpCtx->ns, &builder);
        if (!status.isOK()) {
            uasserted(40481,
                      str::stream() << "Unable to retrieve count in $collStats stage: "
                                    << status.reason());
        }
    }

    return {Document(builder.obj())};
}
static void printStorageConfigOptions( std::ostream& out, const strus::ModuleLoaderInterface* moduleLoader, const std::string& config, strus::ErrorBufferInterface* errorhnd)
{
	std::string configstr( config);
	std::string dbname;
	(void)strus::extractStringFromConfigString( dbname, configstr, "database", errorhnd);
	if (errorhnd->hasError()) throw strus::runtime_error(_TXT("cannot evaluate database: %s"), errorhnd->fetchError());
	std::auto_ptr<strus::StorageObjectBuilderInterface>
		storageBuilder( moduleLoader->createStorageObjectBuilder());
	if (!storageBuilder.get()) throw strus::runtime_error(_TXT("failed to create storage object builder"));

	const strus::DatabaseInterface* dbi = storageBuilder->getDatabase( dbname);
	if (!dbi) throw strus::runtime_error(_TXT("failed to get database interface"));
	const strus::StorageInterface* sti = storageBuilder->getStorage();
	if (!sti) throw strus::runtime_error(_TXT("failed to get storage interface"));

	strus::printIndentMultilineString(
				out, 12, dbi->getConfigDescription(
					strus::DatabaseInterface::CmdCreateClient), errorhnd);
	strus::printIndentMultilineString(
				out, 12, sti->getConfigDescription(
					strus::StorageInterface::CmdCreateClient), errorhnd);
}
Esempio n. 3
0
int main( int argc, const char* argv[])
{
	std::auto_ptr<strus::ErrorBufferInterface> errorBuffer( strus::createErrorBuffer_standard( 0, 2));
	if (!errorBuffer.get())
	{
		std::cerr << _TXT("failed to create error buffer") << std::endl;
		return -1;
	}
	g_errorBuffer = errorBuffer.get();

	bool doExit = false;
	int argi = 1;
	std::string logfile;
	std::vector<std::string> moduledirs;
	std::vector<std::string> modules;
	std::vector<std::string> resourcedirs;
	std::vector<std::string> tracecfglist;
	std::string storageconfig;
	bool doCreateIfNotExist = false;
	unsigned int nofThreads = 0;
	unsigned int port = 7181; //... default port
	try
	{
		// Parsing arguments:
		for (; argi < argc; ++argi)
		{
			if (0==std::strcmp( argv[argi], "-h") || 0==std::strcmp( argv[argi], "--help"))
			{
				printUsage();
				doExit = true;
			}
			else if (0==std::strcmp( argv[argi], "-v") || 0==std::strcmp( argv[argi], "--version"))
			{
				std::cerr << "strusRpc version " << STRUS_RPC_VERSION_STRING << std::endl;
				doExit = true;
			}
			else if (0==std::strcmp( argv[argi], "-m") || 0==std::strcmp( argv[argi], "--module"))
			{
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects argument"), "--module");
				modules.push_back( argv[argi]);
			}
			else if (0==std::strcmp( argv[argi], "-M") || 0==std::strcmp( argv[argi], "--moduledir"))
			{
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects argument"), "--moduledir");
				moduledirs.push_back( argv[argi]);
			}
			else if (0==std::strcmp( argv[argi], "-R") || 0==std::strcmp( argv[argi], "--resourcedir"))
			{
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects argument"), "--resourcedir");
				resourcedirs.push_back( argv[argi]);
			}
			else if (0==std::strcmp( argv[argi], "-p") || 0==std::strcmp( argv[argi], "--port"))
			{
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects argument"), "--port");
				try
				{
					port = strus::utils::touint( argv[argi]);
					if (port == 0 || port > 65535)
					{
						throw strus::runtime_error( _TXT("value out of range"));
					}
				}
				catch (const std::runtime_error& err)
				{
					throw strus::runtime_error( _TXT("illegal argument for option %s: %s"), "--port", err.what());
				}
			}
			else if (0==std::strcmp( argv[argi], "-s") || 0==std::strcmp( argv[argi], "--storage"))
			{
				if (!storageconfig.empty()) throw strus::runtime_error( _TXT("option %s or %s specified twice"), "--storage","--configfile");
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects argument"), "--storage");
				storageconfig.append( argv[argi]);
				if (storageconfig.empty()) throw strus::runtime_error(_TXT("option %s with empty argument"), "--storage");
			}
			else if (0==std::strcmp( argv[argi], "-S") || 0==std::strcmp( argv[argi], "--configfile"))
			{
				if (!storageconfig.empty()) throw strus::runtime_error( _TXT("option %s or %s specified twice"), "--storage","--configfile");
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects argument"), "--configfile");
				int ec = strus::readFile( argv[argi], storageconfig);
				if (ec)
				{
					throw strus::runtime_error(_TXT("failed to read configuration file %s (file system error %u)"), argv[argi], ec);
				}
				std::string::iterator di = storageconfig.begin(), de = storageconfig.end();
				for (; di != de; ++di)
				{
					if ((unsigned char)*di < 32) *di = ' ';
				}
				if (storageconfig.empty()) throw strus::runtime_error(_TXT("option %s with empty file"), "--configfile");
			}
			else if (0==std::strcmp( argv[argi], "-c") || 0==std::strcmp( argv[argi], "--create"))
			{
				doCreateIfNotExist = true;
			}
			else if (0==std::strcmp( argv[argi], "-T") || 0==std::strcmp( argv[argi], "--trace"))
			{
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects argument (trace configuration)"), "--trace");
				tracecfglist.push_back( argv[argi]);
			}
			else if (0==std::strcmp( argv[argi], "-t") || 0==std::strcmp( argv[argi], "--threads"))
			{
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects number as argument"), "--threads");
				try
				{
					nofThreads = strus::utils::touint( argv[argi]);
				}
				catch (const std::runtime_error& err)
				{
					throw strus::runtime_error(_TXT("illegal argument for option %s: %s"),"--threads", err.what());
				}
			}
			else if (0==std::strcmp( argv[argi], "-l") || 0==std::strcmp( argv[argi], "--logfile"))
			{
				if (logfile.size()) throw strus::runtime_error(_TXT("duplicate definition of option %s"), "--logfile");
				++argi;
				if (argi == argc) throw strus::runtime_error(_TXT("option %s expects argument"), "--logfile");
				logfile = argv[argi];
				if (logfile.empty()) throw strus::runtime_error(_TXT("empty definition of option %s"), "--logfile");
			}
			else if (argv[argi][0] == '-')
			{
				throw strus::runtime_error(_TXT("unknown option %s"), argv[argi]);
			}
			else
			{
				throw strus::runtime_error( _TXT("no arguments expected (only options)"));
			}
		}
		if (doExit) return 0;
		init_global_context( logfile.empty()?0:logfile.c_str());
		g_errorBuffer->setLogFile( g_glbctx.logf);
		g_errorBuffer->setMaxNofThreads( strus_threadpool_size()+2);

		// Create the global context:
		std::auto_ptr<strus::ModuleLoaderInterface>
			moduleLoader( strus::createModuleLoader( g_errorBuffer));
		g_moduleLoader = moduleLoader.get();
		if (!g_moduleLoader) throw strus::runtime_error( _TXT("failed to create module loader"));

		std::vector<std::string>::const_iterator
			di = moduledirs.begin(), de = moduledirs.end();
		for (; di != de; ++di)
		{
			g_moduleLoader->addModulePath( *di);
		}
		moduleLoader->addSystemModulePath();
		std::vector<std::string>::const_iterator
			mi = modules.begin(), me = modules.end();
		for (; mi != me; ++mi)
		{
			g_moduleLoader->loadModule( *mi);
		}
		std::vector<std::string>::const_iterator
			pi = resourcedirs.begin(), pe = resourcedirs.end();
		for (; pi != pe; ++pi)
		{
			g_moduleLoader->addResourcePath( *pi);
		}
		if (g_errorBuffer->hasError())
		{
			throw strus::runtime_error(_TXT("error in initialization: %s"), g_errorBuffer->fetchError());
		}

		// Declare trace proxy objects:
		typedef strus::Reference<strus::TraceProxy> TraceReference;
		std::vector<TraceReference> trace;
		if (!tracecfglist.empty())
		{
			std::vector<std::string>::const_iterator ti = tracecfglist.begin(), te = tracecfglist.end();
			for (; ti != te; ++ti)
			{
				trace.push_back( new strus::TraceProxy( g_moduleLoader, *ti, g_errorBuffer));
			}
		}

		// Create objects:
		std::auto_ptr<strus::StorageObjectBuilderInterface>
			storageBuilder( g_moduleLoader->createStorageObjectBuilder());
		if (!storageBuilder.get())
		{
			throw strus::runtime_error( _TXT("failed to create storage builder"));
		}
		std::auto_ptr<strus::AnalyzerObjectBuilderInterface>
			analyzerBuilder( g_moduleLoader->createAnalyzerObjectBuilder());
		if (!analyzerBuilder.get())
		{
			throw strus::runtime_error( _TXT("failed to create analyzer builder"));
		}

		// Create proxy objects if tracing enabled:
		std::vector<TraceReference>::const_iterator ti = trace.begin(), te = trace.end();
		for (; ti != te; ++ti)
		{
			strus::AnalyzerObjectBuilderInterface* aproxy = (*ti)->createProxy( analyzerBuilder.get());
			analyzerBuilder.release();
			analyzerBuilder.reset( aproxy);
			strus::StorageObjectBuilderInterface* sproxy = (*ti)->createProxy( storageBuilder.get());
			storageBuilder.release();
			storageBuilder.reset( sproxy);
		}

		std::auto_ptr<strus::StorageClientInterface> storageClient;

		g_storageObjectBuilder = storageBuilder.get();
		g_analyzerObjectBuilder = analyzerBuilder.get();

		if (!storageconfig.empty())
		{
			if (doCreateIfNotExist)
			{
				createStorageIfNotExist( storageconfig);
			}
			storageClient.reset( strus::createStorageClient( g_storageObjectBuilder, g_errorBuffer, storageconfig));
			if (!storageClient.get())
			{
				throw strus::runtime_error( _TXT("failed to create storage client"), storageconfig.c_str());
			}
			std::cerr << _TXT("strus RPC server is hosting storage ") << "'" << storageconfig << "'" << std::endl;
			g_storageClient = storageClient.get();
		}

		// Start server:
		std::cerr << "strus RPC server listening on port " << port << std::endl;
		int err = strus_run_server( (unsigned short)(unsigned int)port, nofThreads, &g_glbctx);
		if (err)
		{
			throw strus::runtime_error( _TXT("server terminated with error (see logs)"));
		}
		std::cerr << _TXT("strus RPC server terminated") << std::endl;

		// Cleanup when done:
		done_global_context();
		return 0;
	}
	catch (const std::exception& e)
	{
		const char* errormsg = g_errorBuffer?g_errorBuffer->fetchError():0;
		if (errormsg)
		{
			std::cerr << e.what() << ": " << errormsg << std::endl;
		}
		else
		{
			std::cerr << e.what() << std::endl;
		}
	}
	std::cerr << _TXT("strus RPC server terminated") << std::endl;
	done_global_context();
	return -1;
}
int main( int argc, const char* argv[])
{
	int rt = 0;
	std::auto_ptr<strus::ErrorBufferInterface> errorBuffer( strus::createErrorBuffer_standard( 0, 2));
	if (!errorBuffer.get())
	{
		std::cerr << _TXT("failed to create error buffer") << std::endl;
		return -1;
	}
	strus::ProgramOptions opt;
	bool printUsageAndExit = false;
	try
	{
		opt = strus::ProgramOptions(
				argc, argv, 8,
				"h,help", "v,version", "license",
				"m,module:", "M,moduledir:",
				"s,storage:", "S,configfile:", "T,trace:");
		if (opt( "help")) printUsageAndExit = true;
		std::auto_ptr<strus::ModuleLoaderInterface> moduleLoader( strus::createModuleLoader( errorBuffer.get()));
		if (!moduleLoader.get()) throw strus::runtime_error(_TXT("failed to create module loader"));
		if (opt("moduledir"))
		{
			std::vector<std::string> modirlist( opt.list("moduledir"));
			std::vector<std::string>::const_iterator mi = modirlist.begin(), me = modirlist.end();
			for (; mi != me; ++mi)
			{
				moduleLoader->addModulePath( *mi);
			}
			moduleLoader->addSystemModulePath();
		}
		if (opt("module"))
		{
			std::vector<std::string> modlist( opt.list("module"));
			std::vector<std::string>::const_iterator mi = modlist.begin(), me = modlist.end();
			for (; mi != me; ++mi)
			{
				if (!moduleLoader->loadModule( *mi))
				{
					throw strus::runtime_error(_TXT("error failed to load module %s"), mi->c_str());
				}
			}
		}
		if (opt("license"))
		{
			std::vector<std::string> licenses_3rdParty = moduleLoader->get3rdPartyLicenseTexts();
			std::vector<std::string>::const_iterator ti = licenses_3rdParty.begin(), te = licenses_3rdParty.end();
			if (ti != te) std::cout << _TXT("3rd party licenses:") << std::endl;
			for (; ti != te; ++ti)
			{
				std::cout << *ti << std::endl;
			}
			std::cerr << std::endl;
			if (!printUsageAndExit) return 0;
		}
		if (opt( "version"))
		{
			std::cout << _TXT("Strus utilities version ") << STRUS_UTILITIES_VERSION_STRING << std::endl;
			std::cout << _TXT("Strus module version ") << STRUS_MODULE_VERSION_STRING << std::endl;
			std::cout << _TXT("Strus rpc version ") << STRUS_RPC_VERSION_STRING << std::endl;
			std::cout << _TXT("Strus trace version ") << STRUS_TRACE_VERSION_STRING << std::endl;
			std::cout << _TXT("Strus storage version ") << STRUS_STORAGE_VERSION_STRING << std::endl;
			std::cout << _TXT("Strus base version ") << STRUS_BASE_VERSION_STRING << std::endl;
			std::vector<std::string> versions_3rdParty = moduleLoader->get3rdPartyVersionTexts();
			std::vector<std::string>::const_iterator vi = versions_3rdParty.begin(), ve = versions_3rdParty.end();
			if (vi != ve) std::cout << _TXT("3rd party versions:") << std::endl;
			for (; vi != ve; ++vi)
			{
				std::cout << *vi << std::endl;
			}
			if (!printUsageAndExit) return 0;
		}
		else if (!printUsageAndExit)
		{
			if (opt.nofargs() > 1)
			{
				std::cerr << _TXT("too many arguments") << std::endl;
				printUsageAndExit = true;
				rt = 1;
			}
		}
		std::string storagecfg;
		int nof_storagecfg = 0;
		if (opt("configfile"))
		{
			nof_storagecfg += 1;
			std::string configfile = opt[ "configfile"];
			int ec = strus::readFile( configfile, storagecfg);
			if (ec) throw strus::runtime_error(_TXT("failed to read configuration file %s (errno %u)"), configfile.c_str(), ec);

			std::string::iterator di = storagecfg.begin(), de = storagecfg.end();
			for (; di != de; ++di)
			{
				if ((unsigned char)*di < 32) *di = ' ';
			}
		}
		if (opt("storage"))
		{
			nof_storagecfg += 1;
			storagecfg = opt[ "storage"];
		}
		if (opt.nofargs() == 1)
		{
			std::cerr << _TXT("warning: passing storage as first parameter instead of option -s (deprecated)") << std::endl;
			nof_storagecfg += 1;
			storagecfg = opt[0];
		}
		if (nof_storagecfg > 1)
		{
			std::cerr << _TXT("conflicting configuration options specified: --storage and --configfile") << std::endl;
			rt = 10003;
			printUsageAndExit = true;
		}
		else if (!printUsageAndExit && nof_storagecfg == 0)
		{
			std::cerr << _TXT("missing configuration option: --storage or --configfile has to be defined") << std::endl;
			rt = 10004;
			printUsageAndExit = true;
		}
		if (printUsageAndExit)
		{
			std::cout << _TXT("usage:") << " strusCreate [options]" << std::endl;
			std::cout << _TXT("description: Creates a storage with its key value store database.") << std::endl;
			std::cout << _TXT("options:") << std::endl;
			std::cout << "-h|--help" << std::endl;
			std::cout << "    " << _TXT("Print this usage and do nothing else") << std::endl;
			std::cout << "-v|--version" << std::endl;
			std::cout << "    " << _TXT("Print the program version and do nothing else") << std::endl;
			std::cout << "--license" << std::endl;
			std::cout << "    " << _TXT("Print 3rd party licences requiring reference") << std::endl;
			std::cout << "-m|--module <MOD>" << std::endl;
			std::cout << "    " << _TXT("Load components from module <MOD>") << std::endl;
			std::cout << "-M|--moduledir <DIR>" << std::endl;
			std::cout << "    " << _TXT("Search modules to load first in <DIR>") << std::endl;
			std::cout << "-s|--storage <CONFIG>" << std::endl;
			std::cout << "    " << _TXT("Define the storage configuration string as <CONFIG>") << std::endl;
			std::cout << "    " << _TXT("<CONFIG> is a semicolon ';' separated list of assignments:") << std::endl;
			printStorageConfigOptions( std::cout, moduleLoader.get(), storagecfg, errorBuffer.get());
			std::cout << "-S|--configfile <FILENAME>" << std::endl;
			std::cout << "    " << _TXT("Define the storage configuration file as <FILENAME>") << std::endl;
			std::cout << "    " << _TXT("<FILENAME> is a file containing the configuration string") << std::endl;
			std::cout << "-T|--trace <CONFIG>" << std::endl;
			std::cout << "    " << _TXT("Print method call traces configured with <CONFIG>") << std::endl;
			std::cout << "    " << strus::string_format( _TXT("Example: %s"), "-T \"log=dump;file=stdout\"") << std::endl;
			return rt;
		}
		// Declare trace proxy objects:
		typedef strus::Reference<strus::TraceProxy> TraceReference;
		std::vector<TraceReference> trace;
		if (opt("trace"))
		{
			std::vector<std::string> tracecfglist( opt.list("trace"));
			std::vector<std::string>::const_iterator ti = tracecfglist.begin(), te = tracecfglist.end();
			for (; ti != te; ++ti)
			{
				trace.push_back( new strus::TraceProxy( moduleLoader.get(), *ti, errorBuffer.get()));
			}
		}

		// Create root object:
		std::auto_ptr<strus::StorageObjectBuilderInterface>
			storageBuilder( moduleLoader->createStorageObjectBuilder());
		if (!storageBuilder.get()) throw strus::runtime_error(_TXT("failed to create storage object builder"));

		// Create proxy objects if tracing enabled:
		std::vector<TraceReference>::const_iterator ti = trace.begin(), te = trace.end();
		for (; ti != te; ++ti)
		{
			strus::StorageObjectBuilderInterface* sproxy = (*ti)->createProxy( storageBuilder.get());
			storageBuilder.release();
			storageBuilder.reset( sproxy);
		}

		// Create objects:
		std::string dbname;
		(void)strus::extractStringFromConfigString( dbname, storagecfg, "database", errorBuffer.get());

		const strus::DatabaseInterface* dbi = storageBuilder->getDatabase( dbname);
		if (!dbi) throw strus::runtime_error(_TXT("failed to get database interface"));
		const strus::StorageInterface* sti = storageBuilder->getStorage();
		if (!sti) throw strus::runtime_error(_TXT("failed to get storage interface"));

		if (!sti->createStorage( storagecfg, dbi))
		{
			throw strus::runtime_error(_TXT("failed to create storage"));
		}
		if (errorBuffer->hasError())
		{
			throw strus::runtime_error(_TXT("unhandled error in create storage"));
		}
		std::cerr << _TXT("storage successfully created.") << std::endl;
		return 0;
	}
	catch (const std::bad_alloc&)
	{
		std::cerr << _TXT("ERROR ") << _TXT("out of memory") << std::endl;
	}
	catch (const std::runtime_error& e)
	{
		const char* errormsg = errorBuffer->fetchError();
		if (errormsg)
		{
			std::cerr << _TXT("ERROR ") << e.what() << ": " << errormsg << std::endl;
		}
		else
		{
			std::cerr << _TXT("ERROR ") << e.what() << std::endl;
		}
	}
	catch (const std::exception& e)
	{
		std::cerr << _TXT("EXCEPTION ") << e.what() << std::endl;
	}
	return -1;
}