void Ice::stringSeqToArgs(const StringSeq& args, int& argc, char* argv[]) { // // Shift all elements in argv which are present in args to the // beginning of argv. // int i = 0; while(i < argc) { if(find(args.begin(), args.end(), argv[i]) == args.end()) { for(int j = i; j < argc - 1; j++) { argv[j] = argv[j + 1]; } --argc; } else { ++i; } } // // Make sure that argv[argc] == 0, the ISO C++ standard requires this. // if(argv) { argv[argc] = 0; } }
IceInternal::ProxyFactory::ProxyFactory(const InstancePtr& instance) : _instance(instance) { StringSeq retryValues = _instance->initializationData().properties->getPropertyAsList("Ice.RetryIntervals"); if(retryValues.size() == 0) { _retryIntervals.push_back(0); } else { for(StringSeq::const_iterator p = retryValues.begin(); p != retryValues.end(); ++p) { istringstream value(*p); int v; if(!(value >> v) || !value.eof()) { v = 0; } // // If -1 is the first value, no retry and wait intervals. // if(v == -1 && _retryIntervals.empty()) { break; } _retryIntervals.push_back(v > 0 ? v : 0); } } }
void ScriptSystem::getClassList(const char* prefix, bool sort, StringSeq& result) const { ClassInfoDict::const_iterator it = m_classInfoReg.begin(); size_t prefixlen = 0; if (prefix) { prefixlen = strlen(prefix); } for (; it != m_classInfoReg.end(); ++it) { ClassInfo* ci = it->second; if (prefixlen) { if (strncmp(prefix, ci->m_className.c_str(), prefixlen) != 0) { continue; } result.push_back(ci->m_className.c_str() + prefixlen); } else { result.push_back(ci->m_className); } } if (sort) { std::sort(result.begin(), result.end(), std::less<String>()); } }
void golem::findSensor(const Sensor::Map& sensors, const StringSeq& idSeq, Sensor::Seq& sensorSeq) { for (StringSeq::const_iterator i = idSeq.begin(); i != idSeq.end(); ++i) { golem::Sensor::Map::const_iterator pSensor = std::find_if(sensors.begin(), sensors.end(), [=](const golem::Sensor::Map::value_type& val) -> bool { return val.first == *i; }); if (pSensor == sensors.end()) throw Message(Message::LEVEL_CRIT, "findSensor(): unknown sensor id: %s", i->c_str()); sensorSeq.push_back(pSensor->second.get()); } }
void Ice::stringSeqToArgs(const StringSeq& args, int& argc, const wchar_t* argv[]) { // // Don't need to use a wide string converter argv is expected to // come from Windows API. // const StringConverterPtr converter = getProcessStringConverter(); // // Shift all elements in argv which are present in args to the // beginning of argv. We record the original value of argc so // that we can know later if we've shifted the array. // const int argcOrig = argc; int i = 0; while(i < argc) { if(find(args.begin(), args.end(), wstringToString(argv[i], converter)) == args.end()) { for(int j = i; j < argc - 1; j++) { argv[j] = argv[j + 1]; } --argc; } else { ++i; } } // // Make sure that argv[argc] == 0, the ISO C++ standard requires this. // We can only do this if we've shifted the array, otherwise argv[argc] // may point to an invalid address. // if(argv && argcOrig != argc) { argv[argc] = 0; } }
void Ice::stringSeqToArgs(const StringSeq& args, int& argc, char* argv[]) { // // Shift all elements in argv which are present in args to the // beginning of argv. We record the original value of argc so // that we can know later if we've shifted the array. // const int argcOrig = argc; int i = 0; while(i < argc) { if(find(args.begin(), args.end(), argv[i]) == args.end()) { for(int j = i; j < argc - 1; j++) { argv[j] = argv[j + 1]; } --argc; } else { ++i; } } // // Make sure that argv[argc] == 0, the ISO C++ standard requires this. // We can only do this if we've shifted the array, otherwise argv[argc] // may point to an invalid address. // if(argv && argcOrig != argc) { argv[argc] = 0; } }
IceBox::ServiceManagerI::ServiceManagerI(CommunicatorPtr communicator, int& argc, char* argv[]) : _communicator(communicator), _adminEnabled(false), _pendingStatusChanges(false), _traceServiceObserver(0) { #ifndef ICE_CPP11_MAPPING const_cast<CallbackPtr&>(_observerCompletedCB) = newCallback(this, &ServiceManagerI::observerCompleted); #endif _logger = _communicator->getLogger(); PropertiesPtr props = _communicator->getProperties(); _traceServiceObserver = props->getPropertyAsInt("IceBox.Trace.ServiceObserver"); if(props->getProperty("Ice.Admin.Enabled") == "") { _adminEnabled = props->getProperty("Ice.Admin.Endpoints") != ""; } else { _adminEnabled = props->getPropertyAsInt("Ice.Admin.Enabled") > 0; } if(_adminEnabled) { StringSeq facetSeq = props->getPropertyAsList("Ice.Admin.Facets"); if(!facetSeq.empty()) { _adminFacetFilter.insert(facetSeq.begin(), facetSeq.end()); } } for(int i = 1; i < argc; i++) { _argv.push_back(argv[i]); } }
bool IceBox::ServiceManagerI::start() { try { ServiceManagerPtr obj = this; PropertiesPtr properties = _communicator->getProperties(); // // Create an object adapter. Services probably should NOT share // this object adapter, as the endpoint(s) for this object adapter // will most likely need to be firewalled for security reasons. // ObjectAdapterPtr adapter; if(properties->getProperty("IceBox.ServiceManager.Endpoints") != "") { adapter = _communicator->createObjectAdapter("IceBox.ServiceManager"); Identity identity; identity.category = properties->getPropertyWithDefault("IceBox.InstanceName", "IceBox"); identity.name = "ServiceManager"; adapter->add(obj, identity); } // // Parse the property set with the prefix "IceBox.Service.". These // properties should have the following format: // // IceBox.Service.Foo=entry_point [args] // // We parse the service properties specified in IceBox.LoadOrder // first, then the ones from remaining services. // const string prefix = "IceBox.Service."; PropertyDict services = properties->getPropertiesForPrefix(prefix); PropertyDict::iterator p; StringSeq loadOrder = properties->getPropertyAsList("IceBox.LoadOrder"); vector<StartServiceInfo> servicesInfo; for(StringSeq::const_iterator q = loadOrder.begin(); q != loadOrder.end(); ++q) { p = services.find(prefix + *q); if(p == services.end()) { FailureException ex(__FILE__, __LINE__); ex.reason = "ServiceManager: no service definition for `" + *q + "'"; throw ex; } servicesInfo.push_back(StartServiceInfo(*q, p->second, _argv)); services.erase(p); } for(p = services.begin(); p != services.end(); ++p) { servicesInfo.push_back(StartServiceInfo(p->first.substr(prefix.size()), p->second, _argv)); } // // Check if some services are using the shared communicator in which // case we create the shared communicator now with a property set which // is the union of all the service properties (services which are using // the shared communicator). // PropertyDict sharedCommunicatorServices = properties->getPropertiesForPrefix("IceBox.UseSharedCommunicator."); if(!sharedCommunicatorServices.empty()) { InitializationData initData; initData.properties = createServiceProperties("SharedCommunicator"); for(vector<StartServiceInfo>::iterator q = servicesInfo.begin(); q != servicesInfo.end(); ++q) { if(properties->getPropertyAsInt("IceBox.UseSharedCommunicator." + q->name) <= 0) { continue; } // // Load the service properties using the shared communicator properties as // the default properties. // PropertiesPtr svcProperties = createProperties(q->args, initData.properties); // // Erase properties from the shared communicator which don't exist in the // service properties (which include the shared communicator properties // overriden by the service properties). // PropertyDict allProps = initData.properties->getPropertiesForPrefix(""); for(PropertyDict::iterator p = allProps.begin(); p != allProps.end(); ++p) { if(svcProperties->getProperty(p->first) == "") { initData.properties->setProperty(p->first, ""); } } // // Add the service properties to the shared communicator properties. // PropertyDict props = svcProperties->getPropertiesForPrefix(""); for(PropertyDict::const_iterator r = props.begin(); r != props.end(); ++r) { initData.properties->setProperty(r->first, r->second); } // // Parse <service>.* command line options (the Ice command line options // were parsed by the createProperties above) // q->args = initData.properties->parseCommandLineOptions(q->name, q->args); } _sharedCommunicator = initialize(initData); } // // Start the services. // for(vector<StartServiceInfo>::const_iterator r = servicesInfo.begin(); r != servicesInfo.end(); ++r) { start(r->name, r->entryPoint, r->args); } // // We may want to notify external scripts that the services // have started. This is done by defining the property: // // IceBox.PrintServicesReady=bundleName // // Where bundleName is whatever you choose to call this set of // services. It will be echoed back as "bundleName ready". // // This must be done after start() has been invoked on the // services. // string bundleName = properties->getProperty("IceBox.PrintServicesReady"); if(!bundleName.empty()) { cout << bundleName << " ready" << endl; } // // Register "this" as a facet to the Admin object, and then create // Admin object // try { _communicator->addAdminFacet(this, "IceBox.ServiceManager"); // // Add a Properties facet for each service // for(vector<ServiceInfo>::iterator r = _services.begin(); r != _services.end(); ++r) { const ServiceInfo& info = *r; CommunicatorPtr communicator = info.communicator != 0 ? info.communicator : _sharedCommunicator; _communicator->addAdminFacet(new PropertiesAdminI(communicator->getProperties()), "IceBox.Service." + info.name + ".Properties"); } _communicator->getAdmin(); } catch(const ObjectAdapterDeactivatedException&) { // // Expected if the communicator has been shutdown. // } if(adapter) { try { adapter->activate(); } catch(const ObjectAdapterDeactivatedException&) { // // Expected if the communicator has been shutdown. // } } } catch(const FailureException& ex) { Error out(_logger); out << ex.reason; stopAll(); return false; } catch(const Exception& ex) { Error out(_logger); out << "ServiceManager: " << ex; stopAll(); return false; } return true; }
int Activator::activate(const string& name, const string& exePath, const string& pwdPath, #ifndef _WIN32 uid_t uid, gid_t gid, #endif const Ice::StringSeq& options, const Ice::StringSeq& envs, const ServerIPtr& server) { IceUtil::Monitor< IceUtil::Mutex>::Lock sync(*this); if(_deactivating) { throw string("The node is being shutdown."); } string path = exePath; if(path.empty()) { throw string("The server executable path is empty."); } string pwd = IcePatch2Internal::simplify(pwdPath); #ifdef _WIN32 if(!IceUtilInternal::isAbsolutePath(path)) { if(path.find('/') == string::npos) { // // Get the absolute pathname of the executable. // wchar_t absbuf[_MAX_PATH]; wchar_t* fPart; wstring ext = path.size() <= 4 || path[path.size() - 4] != '.' ? L".exe" : L""; // // IceGrid doesn't support to use string converters, so don't need to use // any string converter in wstringToString conversions. // if(SearchPathW(NULL, IceUtil::stringToWstring(path).c_str(), ext.c_str(), _MAX_PATH, absbuf, &fPart) == 0) { if(_traceLevels->activator > 0) { Trace out(_traceLevels->logger, _traceLevels->activatorCat); out << "couldn't find `" << path << "' executable."; } throw string("Couldn't find `" + path + "' executable."); } path = IceUtil::wstringToString(absbuf); } else if(!pwd.empty()) { path = pwd + "/" + path; } } // // Get the absolute pathname of the working directory. // // IceGrid doesn't support to use string converters, so // don't need to use any string converter in stringToWstring // conversions. // if(!pwd.empty()) { wchar_t absbuf[_MAX_PATH]; if(_wfullpath(absbuf, IceUtil::stringToWstring(pwd).c_str(), _MAX_PATH) == NULL) { if(_traceLevels->activator > 0) { Trace out(_traceLevels->logger, _traceLevels->activatorCat); out << "cannot convert `" << pwd << "' into an absolute path"; } throw string("The server working directory path `" + pwd + "' can't be converted into an absolute path."); } pwd = IceUtil::wstringToString(absbuf); } #endif // // Setup arguments. // StringSeq args; args.push_back(path); args.insert(args.end(), options.begin(), options.end()); if(_traceLevels->activator > 0) { Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat); out << "activating server `" << name << "'"; if(_traceLevels->activator > 1) { out << "\n"; out << "path = " << path << "\n"; if(pwd.empty()) { string cwd; if(IceUtilInternal::getcwd(cwd) == 0) { out << "pwd = " << cwd << "\n"; } } else { out << "pwd = " << pwd << "\n"; } #ifndef _WIN32 out << "uid/gid = " << uid << "/" << gid << "\n"; #endif if(!envs.empty()) { out << "envs = " << toString(envs, ", ") << "\n"; } if(!args.empty()) { out << "args = " << toString(args); } } } // // Activate and create. // #ifdef _WIN32 // // Compose command line. // string cmd; for(StringSeq::const_iterator p = args.begin(); p != args.end(); ++p) { if(p != args.begin()) { cmd.push_back(' '); } // // Enclose arguments containing spaces in double quotes. // if((*p).find(' ') != string::npos) { cmd.push_back('"'); cmd.append(*p); cmd.push_back('"'); } else { cmd.append(*p); } } // // IceGrid doesn't support to use string converters, so don't need to use // any string converter in stringToWstring conversions. // wstring wpwd = IceUtil::stringToWstring(pwd); const wchar_t* dir = !wpwd.empty() ? wpwd.c_str() : NULL; // // Make a copy of the command line. // wchar_t* cmdbuf = _wcsdup(IceUtil::stringToWstring(cmd).c_str()); // // Create the environment block for the child process. We start with the environment // of this process, and then merge environment variables from the server description. // Since Windows is case insensitive wrt environment variables we convert the keys to // uppercase to ensure matches are found. // const wchar_t* env = NULL; wstring envbuf; if(!envs.empty()) { map<wstring, wstring, UnicodeStringLess> envMap; LPVOID parentEnv = GetEnvironmentStringsW(); const wchar_t* var = reinterpret_cast<const wchar_t*>(parentEnv); if(*var == L'=') { // // The environment block may start with some information about the // current drive and working directory. This is indicated by a leading // '=' character, so we skip to the first '\0' byte. // while(*var != L'\0') var++; var++; } while(*var != L'\0') { wstring s(var); wstring::size_type pos = s.find(L'='); if(pos != wstring::npos) { envMap[s.substr(0, pos)] = s.substr(pos + 1); } var += s.size(); var++; // Skip the '\0' byte } FreeEnvironmentStringsW(static_cast<wchar_t*>(parentEnv)); for(StringSeq::const_iterator p = envs.begin(); p != envs.end(); ++p) { // // IceGrid doesn't support to use string converters, so don't need to use // any string converter in stringToWstring conversions. // wstring s = IceUtil::stringToWstring(*p); wstring::size_type pos = s.find(L'='); if(pos != wstring::npos) { envMap[s.substr(0, pos)] = s.substr(pos + 1); } } for(map<wstring, wstring, UnicodeStringLess>::const_iterator q = envMap.begin(); q != envMap.end(); ++q) { envbuf.append(q->first); envbuf.push_back(L'='); envbuf.append(q->second); envbuf.push_back(L'\0'); } envbuf.push_back(L'\0'); env = envbuf.c_str(); } Process process; STARTUPINFOW si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); BOOL b = CreateProcessW( NULL, // Executable cmdbuf, // Command line NULL, // Process attributes NULL, // Thread attributes FALSE, // Do NOT inherit handles CREATE_NEW_PROCESS_GROUP | CREATE_UNICODE_ENVIRONMENT, // Process creation flags (LPVOID)env, // Process environment dir, // Current directory &si, // Startup info &pi // Process info ); free(cmdbuf); if(!b) { throw IceUtilInternal::lastErrorToString(); } // // Caller is responsible for closing handles in PROCESS_INFORMATION. We don't need to // keep the thread handle, so we close it now. The process handle will be closed later. // CloseHandle(pi.hThread); process.activator = this; process.pid = pi.dwProcessId; process.hnd = pi.hProcess; process.server = server; map<string, Process>::iterator it = _processes.insert(make_pair(name, process)).first; Process* pp = &it->second; if(!RegisterWaitForSingleObject(&pp->waithnd, pp->hnd, activatorWaitCallback, pp, INFINITE, WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) { throw IceUtilInternal::lastErrorToString(); } // // Don't print the following trace, this might interfer with the // output of the started process if it fails with an error message. // // if(_traceLevels->activator > 0) // { // Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat); // out << "activated server `" << name << "' (pid = " << pi.dwProcessId << ")"; // } return static_cast<Ice::Int>(process.pid); #else int fds[2]; if(pipe(fds) != 0) { SyscallException ex(__FILE__, __LINE__); ex.error = getSystemErrno(); throw ex; } int errorFds[2]; if(pipe(errorFds) != 0) { SyscallException ex(__FILE__, __LINE__); ex.error = getSystemErrno(); throw ex; } // // Convert to standard argc/argv. // IceUtilInternal::ArgVector av(args); IceUtilInternal::ArgVector env(envs); // // Current directory // const char* pwdCStr = pwd.c_str(); pid_t pid = fork(); if(pid == -1) { SyscallException ex(__FILE__, __LINE__); ex.error = getSystemErrno(); throw ex; } if(pid == 0) // Child process. { // // Until exec, we can only use async-signal safe functions // // // Unblock signals blocked by IceUtil::CtrlCHandler. // sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, SIGHUP); sigaddset(&sigs, SIGINT); sigaddset(&sigs, SIGTERM); sigprocmask(SIG_UNBLOCK, &sigs, 0); // // Change the uid/gid under which the process will run. // if(setgid(gid) == -1) { ostringstream os; os << gid; reportChildError(getSystemErrno(), errorFds[1], "cannot set process group id", os.str().c_str(), _traceLevels); } errno = 0; struct passwd* pw = getpwuid(uid); if(!pw) { if(errno) { reportChildError(getSystemErrno(), errorFds[1], "cannot read the password database", "", _traceLevels); } else { ostringstream os; os << uid; reportChildError(getSystemErrno(), errorFds[1], "unknown user uid" , os.str().c_str(), _traceLevels); } } // // Don't initialize supplementary groups if we are not running as root. // if(getuid() == 0 && initgroups(pw->pw_name, gid) == -1) { ostringstream os; os << pw->pw_name; reportChildError(getSystemErrno(), errorFds[1], "cannot initialize process supplementary group access list for user", os.str().c_str(), _traceLevels); } if(setuid(uid) == -1) { ostringstream os; os << uid; reportChildError(getSystemErrno(), errorFds[1], "cannot set process user id", os.str().c_str(), _traceLevels); } // // Assign a new process group for this process. // setpgid(0, 0); // // Close all file descriptors, except for standard input, // standard output, standard error, and the write side // of the newly created pipe. // int maxFd = static_cast<int>(sysconf(_SC_OPEN_MAX)); for(int fd = 3; fd < maxFd; ++fd) { if(fd != fds[1] && fd != errorFds[1]) { close(fd); } } for(int i = 0; i < env.argc; i++) { // // Each env is leaked on purpose ... see man putenv(). // if(putenv(strdup(env.argv[i])) != 0) { reportChildError(errno, errorFds[1], "cannot set environment variable", env.argv[i], _traceLevels); } } // // Change working directory. // if(strlen(pwdCStr) != 0) { if(chdir(pwdCStr) == -1) { reportChildError(errno, errorFds[1], "cannot change working directory to", pwdCStr, _traceLevels); } } // // Close on exec the error message file descriptor. // int flags = fcntl(errorFds[1], F_GETFD); flags |= 1; // FD_CLOEXEC if(fcntl(errorFds[1], F_SETFD, flags) == -1) { close(errorFds[1]); errorFds[1] = -1; } if(execvp(av.argv[0], av.argv) == -1) { if(errorFds[1] != -1) { reportChildError(errno, errorFds[1], "cannot execute", av.argv[0], _traceLevels); } else { reportChildError(errno, fds[1], "cannot execute", av.argv[0], _traceLevels); } } } else // Parent process. { close(fds[1]); close(errorFds[1]); // // Read a potential error message over the error message pipe. // char s[16]; ssize_t rs; string message; while((rs = read(errorFds[0], &s, 16)) > 0) { message.append(s, rs); } // // If an error occured before the exec() we do some cleanup and throw. // if(!message.empty()) { close(fds[0]); close(errorFds[0]); waitPid(pid); throw message; } // // Otherwise, the exec() was successfull and we don't need the error message // pipe anymore. // close(errorFds[0]); Process process; process.pid = pid; process.pipeFd = fds[0]; process.server = server; _processes.insert(make_pair(name, process)); int flags = fcntl(process.pipeFd, F_GETFL); flags |= O_NONBLOCK; fcntl(process.pipeFd, F_SETFL, flags); setInterrupt(); // // Don't print the following trace, this might interfere with the // output of the started process if it fails with an error message. // // if(_traceLevels->activator > 0) // { // Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat); // out << "activated server `" << name << "' (pid = " << pid << ")"; // } } return pid; #endif }
void Ice::PluginManagerI::loadPlugins(int& argc, const char* argv[]) { assert(_communicator); StringSeq cmdArgs = argsToStringSeq(argc, argv); const string prefix = "Ice.Plugin."; PropertiesPtr properties = _communicator->getProperties(); PropertyDict plugins = properties->getPropertiesForPrefix(prefix); // // First, load static plugin factories which were setup to load on // communicator initialization. If a matching plugin property is // set, we load the plugin with the plugin specification. The // entryPoint will be ignored but the rest of the plugin // specification might be used. // if(loadOnInitialization) { for(vector<string>::const_iterator p = loadOnInitialization->begin(); p != loadOnInitialization->end(); ++p) { string property = prefix + *p; PropertyDict::iterator r = plugins.find(property + ".cpp"); if(r == plugins.end()) { r = plugins.find(property); } else { plugins.erase(property); } if(r != plugins.end()) { loadPlugin(*p, r->second, cmdArgs); plugins.erase(r); } else { loadPlugin(*p, "", cmdArgs); } } } // // Next, load and initialize the plug-ins defined in the property // set with the prefix "Ice.Plugin.". These properties should have // the following format: // // Ice.Plugin.name[.<language>]=entry_point [args] // // If the Ice.PluginLoadOrder property is defined, load the // specified plug-ins in the specified order, then load any // remaining plug-ins. // StringSeq loadOrder = properties->getPropertyAsList("Ice.PluginLoadOrder"); for(StringSeq::const_iterator p = loadOrder.begin(); p != loadOrder.end(); ++p) { string name = *p; if(findPlugin(name)) { PluginInitializationException ex(__FILE__, __LINE__); ex.reason = "plug-in `" + name + "' already loaded"; throw ex; } string property = prefix + name; PropertyDict::iterator r = plugins.find(property + ".cpp"); if(r == plugins.end()) { r = plugins.find(property); } else { plugins.erase(property); } if(r != plugins.end()) { loadPlugin(name, r->second, cmdArgs); plugins.erase(r); } else { PluginInitializationException ex(__FILE__, __LINE__); ex.reason = "plug-in `" + name + "' not defined"; throw ex; } } // // Load any remaining plug-ins that weren't specified in PluginLoadOrder. // while(!plugins.empty()) { PropertyDict::iterator p = plugins.begin(); string name = p->first.substr(prefix.size()); size_t dotPos = name.find_last_of('.'); if(dotPos != string::npos) { string suffix = name.substr(dotPos + 1); if(suffix == "java" || suffix == "clr") { // // Ignored // plugins.erase(p); } else if(suffix == "cpp") { name = name.substr(0, dotPos); loadPlugin(name, p->second, cmdArgs); plugins.erase(p); plugins.erase(prefix + name); } else { // // Name is just a regular name that happens to contain a dot // dotPos = string::npos; } } if(dotPos == string::npos) { // // Is there a .cpp entry? // PropertyDict::iterator q = plugins.find(prefix + name + ".cpp"); if(q != plugins.end()) { plugins.erase(p); p = q; } loadPlugin(name, p->second, cmdArgs); plugins.erase(p); } } stringSeqToArgs(cmdArgs, argc, argv); }
Freeze::MapDb::MapDb(const ConnectionIPtr& connection, const string& dbName, const string& key, const string& value, const KeyCompareBasePtr& keyCompare, const vector<MapIndexBasePtr>& indices, bool createDb) : Db(connection->dbEnv()->getEnv(), 0), _communicator(connection->communicator()), _dbName(dbName), _trace(connection->trace()), _keyCompare(keyCompare) { if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "opening Db \"" << _dbName << "\""; } Catalog catalog(connection, _catalogName); TransactionPtr tx = connection->currentTransaction(); bool ownTx = (tx == 0); for(;;) { try { if(ownTx) { tx = 0; tx = connection->beginTransaction(); } Catalog::iterator ci = catalog.find(_dbName); if(ci != catalog.end()) { if(ci->second.evictor) { throw DatabaseException(__FILE__, __LINE__, _dbName + " is an evictor database"); } _key = ci->second.key; _value = ci->second.value; checkTypes(key, value); } else { _key = key; _value = value; } set_app_private(this); if(_keyCompare->compareEnabled()) { set_bt_compare(&customCompare); } PropertiesPtr properties = _communicator->getProperties(); string propPrefix = "Freeze.Map." + _dbName + "."; int btreeMinKey = properties->getPropertyAsInt(propPrefix + "BtreeMinKey"); if(btreeMinKey > 2) { if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Setting \"" << _dbName << "\"'s btree minkey to " << btreeMinKey; } set_bt_minkey(btreeMinKey); } bool checksum = properties->getPropertyAsInt(propPrefix + "Checksum") > 0; if(checksum) { if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Turning checksum on for \"" << _dbName << "\""; } set_flags(DB_CHKSUM); } int pageSize = properties->getPropertyAsInt(propPrefix + "PageSize"); if(pageSize > 0) { if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Setting \"" << _dbName << "\"'s pagesize to " << pageSize; } set_pagesize(pageSize); } DbTxn* txn = getTxn(tx); u_int32_t flags = DB_THREAD; if(createDb) { flags |= DB_CREATE; } open(txn, Ice::nativeToUTF8(_communicator, _dbName).c_str(), 0, DB_BTREE, flags, FREEZE_DB_MODE); StringSeq oldIndices; StringSeq newIndices; size_t oldSize = 0; CatalogIndexList catalogIndexList(connection, _catalogIndexListName); if(createDb) { CatalogIndexList::iterator cil = catalogIndexList.find(_dbName); if(cil != catalogIndexList.end()) { oldIndices = cil->second; oldSize = oldIndices.size(); } } for(vector<MapIndexBasePtr>::const_iterator p = indices.begin(); p != indices.end(); ++p) { const MapIndexBasePtr& indexBase = *p; assert(indexBase->_impl == 0); assert(indexBase->_communicator == 0); indexBase->_communicator = connection->communicator(); auto_ptr<MapIndexI> indexI; try { indexI.reset(new MapIndexI(connection, *this, txn, createDb, indexBase)); } catch(const DbDeadlockException&) { throw; } catch(const DbException& dx) { string message = "Error while opening index \"" + _dbName + "." + indexBase->name() + "\": " + dx.what(); throw DatabaseException(__FILE__, __LINE__, message); } #ifndef NDEBUG bool inserted = #endif _indices.insert(IndexMap::value_type(indexBase->name(), indexI.get())).second; assert(inserted); indexBase->_impl = indexI.release(); if(createDb) { newIndices.push_back(indexBase->name()); oldIndices.erase(std::remove(oldIndices.begin(), oldIndices.end(), indexBase->name()), oldIndices.end()); } } if(ci == catalog.end()) { CatalogData catalogData; catalogData.evictor = false; catalogData.key = key; catalogData.value = value; catalog.put(Catalog::value_type(_dbName, catalogData)); } if(createDb) { // // Remove old indices and write the new ones // bool indexRemoved = false; for(StringSeq::const_iterator q = oldIndices.begin(); q != oldIndices.end(); ++q) { const string& index = *q; if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "removing old index \"" << index << "\" on Db \"" << _dbName << "\""; } try { connection->removeMapIndex(_dbName, *q); indexRemoved = true; } catch(const IndexNotFoundException&) { // Ignored if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "index \"" << index << "\" on Db \"" << _dbName << "\" does not exist"; } } } if(indexRemoved || oldSize != newIndices.size()) { if(newIndices.size() == 0) { catalogIndexList.erase(_dbName); if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Removed catalogIndexList entry for Db \"" << _dbName << "\""; } } else { catalogIndexList.put(CatalogIndexList::value_type(_dbName, newIndices)); if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Updated catalogIndexList entry for Db \"" << _dbName << "\""; } } } } if(ownTx) { tx->commit(); } break; // for(;;) } catch(const DbDeadlockException& dx) { if(ownTx) { if(connection->deadlockWarning()) { Warning out(connection->communicator()->getLogger()); out << "Deadlock in Freeze::MapDb::MapDb on Map \"" << _dbName << "\"; retrying ..."; } // // Ignored, try again // } else { throw DeadlockException(__FILE__, __LINE__, dx.what(), tx); } } catch(const DbException& dx) { if(ownTx) { try { tx->rollback(); } catch(...) { } } string message = "Error while opening Db \"" + _dbName + "\": " + dx.what(); throw DatabaseException(__FILE__, __LINE__, message); } catch(...) { if(ownTx && tx != 0) { try { tx->rollback(); } catch(...) { } } throw; } } }
int main(int argc, char* argv[]) #endif { Ice::StringSeq originalArgs = Ice::argsToStringSeq(argc, argv); assert(originalArgs.size() > 0); const string appName = originalArgs[0]; string dataDir; StringSeq fileSeq; int compress = 1; bool verbose; bool caseInsensitive; IceUtilInternal::Options opts; opts.addOpt("h", "help"); opts.addOpt("v", "version"); opts.addOpt("z", "compress"); opts.addOpt("Z", "no-compress"); opts.addOpt("V", "verbose"); opts.addOpt("i", "case-insensitive"); vector<string> args; try { args = opts.parse(originalArgs); } catch(const IceUtilInternal::BadOptException& e) { cerr << e.reason << endl; usage(appName); return EXIT_FAILURE; } if(opts.isSet("help")) { usage(appName); return EXIT_SUCCESS; } if(opts.isSet("version")) { cout << ICE_STRING_VERSION << endl; return EXIT_SUCCESS; } bool doCompress = opts.isSet("compress"); bool dontCompress = opts.isSet("no-compress"); if(doCompress && dontCompress) { cerr << appName << ": only one of -z and -Z are mutually exclusive" << endl; usage(appName); return EXIT_FAILURE; } if(doCompress) { compress = 2; } else if(dontCompress) { compress = 0; } verbose = opts.isSet("verbose"); caseInsensitive = opts.isSet("case-insensitive"); if(args.empty()) { cerr << appName << ": no data directory specified" << endl; usage(appName); return EXIT_FAILURE; } dataDir = simplify(args[0]); for(vector<string>::size_type i = 1; i < args.size(); ++i) { fileSeq.push_back(simplify(args[i])); } try { string absDataDir = dataDir; string cwd; if(IceUtilInternal::getcwd(cwd) != 0) { throw "cannot get the current directory:\n" + IceUtilInternal::lastErrorToString(); } if(!IceUtilInternal::isAbsolutePath(absDataDir)) { absDataDir = simplify(cwd + '/' + absDataDir); } for(StringSeq::iterator p = fileSeq.begin(); p != fileSeq.end(); ++p) { if(!IceUtilInternal::isAbsolutePath(*p)) { *p = cwd + '/' + *p; } } // // We must call simplify() here: under Cygwin, any path starting with // a double slash simply doesn't work. But, if dataDir is "/", we end // up with paths that start with "//" unless we call simplify(). // string absDataDirWithSlash = simplify(absDataDir + '/'); for(StringSeq::iterator p = fileSeq.begin(); p != fileSeq.end(); ++p) { if(p->compare(0, absDataDirWithSlash.size(), absDataDirWithSlash) != 0) { throw "`" + *p + "' is not a path in `" + dataDir + "'"; } p->erase(0, absDataDirWithSlash.size()); } LargeFileInfoSeq infoSeq; if(fileSeq.empty()) { CalcCB calcCB; if(!getFileInfoSeq(absDataDir, compress, verbose ? &calcCB : 0, infoSeq)) { return EXIT_FAILURE; } } else { loadFileInfoSeq(absDataDir, infoSeq); for(StringSeq::iterator p = fileSeq.begin(); p != fileSeq.end(); ++p) { LargeFileInfoSeq partialInfoSeq; CalcCB calcCB; if(!getFileInfoSeqSubDir(absDataDir, *p, compress, verbose ? &calcCB : 0, partialInfoSeq)) { return EXIT_FAILURE; } LargeFileInfoSeq newInfoSeq; newInfoSeq.reserve(infoSeq.size()); set_difference(infoSeq.begin(), infoSeq.end(), partialInfoSeq.begin(), partialInfoSeq.end(), back_inserter(newInfoSeq), FileInfoPathLess()); infoSeq.swap(newInfoSeq); newInfoSeq.clear(); newInfoSeq.reserve(infoSeq.size() + partialInfoSeq.size()); set_union(infoSeq.begin(), infoSeq.end(), partialInfoSeq.begin(), partialInfoSeq.end(), back_inserter(newInfoSeq), FileInfoPathLess()); infoSeq.swap(newInfoSeq); } } if(caseInsensitive) { LargeFileInfoSeq newInfoSeq = infoSeq; sort(newInfoSeq.begin(), newInfoSeq.end(), IFileInfoPathLess()); string ex; LargeFileInfoSeq::iterator p = newInfoSeq.begin(); while((p = adjacent_find(p, newInfoSeq.end(), IFileInfoPathEqual())) != newInfoSeq.end()) { do { ex += '\n' + dataDir + '/' + p->path; ++p; } while(p < newInfoSeq.end() && IFileInfoPathEqual()(*(p - 1), *p)); } if(!ex.empty()) { ex = "duplicate files:" + ex; throw ex; } } saveFileInfoSeq(absDataDir, infoSeq); } catch(const string& ex) { cerr << appName << ": " << ex << endl; return EXIT_FAILURE; } catch(const char* ex) { cerr << appName << ": " << ex << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }