Files
secondo/Algebras/DBService2/SecondoUtilsLocal.cpp
2026-01-23 17:03:45 +08:00

599 lines
20 KiB
C++

/*
1.1.1 Class Implementation
----
This file is part of SECONDO.
Copyright (C) 2017,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
*/
#include <algorithm>
#include <sstream>
#include <boost/thread/mutex.hpp>
#include "CharTransform.h"
#include "NestedList.h"
#include "Profiles.h"
#include "SecParser.h"
#include "ErrorCodes.h"
#include "Algebras/DBService2/DebugOutput.hpp"
#include "Algebras/DBService2/SecondoUtilsLocal.hpp"
#include "Algebras/DBService2/TraceSettings.hpp"
#include "Algebras/DBService2/LockKeeper.hpp"
#include <loguru.hpp>
using namespace std;
using namespace distributed2;
extern CMsg cmsg;
extern boost::recursive_mutex nlparsemtx;
namespace DBService {
void SecondoUtilsLocal::readFromConfigFile(string& resultValue,
const char* section,
const char* key,
const char* defaultValue)
{
printFunction("SecondoUtilsLocal::readFromConfigFile", std::cout);
string secondoConfig = expandVar("$(SECONDO_CONFIG)");
resultValue = SmiProfile::GetParameter(section,
key, defaultValue, secondoConfig);
}
string SecondoUtilsLocal::getSecondoHomeDir() {
string secondoHome;
readFromConfigFile(secondoHome, "Environment", "SecondoHome",
"/secondo/home/is/missing");
return secondoHome;
}
bool SecondoUtilsLocal::executeQuery(const string& queryAsString)
{
// JF
Word queryResult = new Word; SetWord(Address(0));
print("Query (with new Word):", queryAsString, std::cout);
return executeQuery(queryAsString, queryResult);
}
bool SecondoUtilsLocal::prepareQueryForProcessing(
const string& queryAsString,
string& queryAsPreparedNestedListString)
{
printFunction("SecondoUtilsLocal::prepareQueryForProcessing", std::cout);
print("Query:", queryAsString, std::cout);
SecParser secondoParser;
string queryAsNestedListString;
if (secondoParser.Text2List(queryAsString, queryAsNestedListString) != 0)
{
print("could not parse query", std::cout);
return false;
}
print("query converted to nested list string", std::cout);
print("queryAsNestedListString 1", queryAsNestedListString, std::cout);
if(queryAsNestedListString.find("(query ") == 0)
{
queryAsNestedListString.erase(0, strlen("(query "));
print("queryAsNestedListString 2", queryAsNestedListString, std::cout);
queryAsPreparedNestedListString =
queryAsNestedListString.substr(
0, queryAsNestedListString.rfind(")"));
}else
{
queryAsPreparedNestedListString = queryAsNestedListString;
}
print("queryAsPreparedNestedListString",
queryAsPreparedNestedListString, std::cout);
return true;
}
bool SecondoUtilsLocal::executeQuery2(const string& queryAsString)
{
printFunction("SecondoUtilsLocal::executeQuery2", std::cout);
print("Query:", queryAsString, std::cout);
Word queryResult;
string queryAsPreparedNestedListString;
print("Acquiring lock for executeQuery2...", std::cout);
LOG_F(INFO, "%s", "Acquiring lock for utilsMutex...");
boost::lock_guard<boost::mutex> lock(utilsMutex);
LOG_F(INFO, "%s", "Successfully acquired lock for utilsMutex...");
print("Done acquiring lock for executeQuery2.", std::cout);
print("Preparing query for processing...", std::cout);
if(!prepareQueryForProcessing(
queryAsString,
queryAsPreparedNestedListString))
{
return false;
}
print("Done preparing query for processing.", std::cout);
int traceLevel =
TraceSettings::getInstance()->isDebugTraceOn() ? 3 : 0;
print("Actually executing query now ...", std::cout);
// LOG_F(INFO, "%s", "Acquiring lock for executeQuery2...");
// boost::lock_guard<boost::recursive_mutex> queryProcessorGuard(
// // Dereference the shared_ptr to the mutex
// *LockKeeper::getInstance()->getQueryProcessorMutex()
// );
// LOG_F(INFO, "%s", "Successfully acquired lock for QueryProcessorMutex.");
// // Establishing a timeout for locks
// std::shared_ptr<boost::timed_mutex> qpMutex =
// LockKeeper::getInstance()->getQueryProcessorMutex();
// boost::unique_lock<boost::timed_mutex>
// queryProcessorLock{ *qpMutex, boost::try_to_lock };
// if(queryProcessorLock.owns_lock() ||
// queryProcessorLock.try_lock_for(boost::chrono::seconds{ 360 })) {
// LOG_F(INFO, "%s", "Successfully acquired QueryProcessorMutex.");
// }
// else {
// LOG_F(ERROR, "%s", "Acquisition of QueryProcessorMutex "
// "failed due to timeout.");
// return false;
// }
return QueryProcessor::ExecuteQuery(
queryAsPreparedNestedListString,
queryResult,
DEFAULT_GLOBAL_MEMORY,
traceLevel);
}
bool SecondoUtilsLocal::executeQuery(const string& queryAsString,
Word& queryResult)
{
printFunction("SecondoUtilsLocal::executeQuery", std::cout);
print("Acquiring lock for executeQuery...", std::cout);
boost::lock_guard<boost::mutex> lock(utilsMutex);
print("Done acquiring lock for executeQuery.", std::cout);
print("QueryAsString", queryAsString, std::cout);
SecParser secondoParser;
string queryAsNestedListString;
if (secondoParser.Text2List(queryAsString, queryAsNestedListString) != 0) {
print("could not parse query", std::cout);
return false;
}
print("Query has been converted to nested list string.", std::cout);
ListExpr queryAsNestedList;
NestedList* nli = SecondoSystem::GetNestedList();
if(!nli->ReadFromString(queryAsNestedListString,
queryAsNestedList))
{
print("could not read nested list from string", std::cout);
return false;
}
print("Nested list string has been converted to nested list", std::cout);
print("QueryAsNestedListString", queryAsNestedListString, std::cout);
bool success = true;
bool correct, evaluable, defined, isFunction = false;
string typeString(""), errorString("");
// LOG_F(INFO, "%s", "Acquiring lock for executeQuery...");
// boost::lock_guard<boost::recursive_mutex> queryProcessorGuard(
// // Dereference the shared_ptr to the mutex
// *LockKeeper::getInstance()->getQueryProcessorMutex()
// );
// // Establishing a timeout for locks
// std::shared_ptr<boost::timed_mutex> qpMutex =
// LockKeeper::getInstance()->getQueryProcessorMutex();
// boost::unique_lock<boost::timed_mutex>
// queryProcessorLock{ *qpMutex, boost::try_to_lock };
// if(queryProcessorLock.owns_lock() ||
// queryProcessorLock.try_lock_for(boost::chrono::seconds{ 360 })) {
// LOG_F(INFO, "%s", "Successfully acquired QueryProcessorMutex.");
// }
// else {
// LOG_F(ERROR, "%s", "Acquisition of QueryProcessorMutex "
// "failed due to timeout.");
// return false;
// }
try
{
success = QueryProcessor::ExecuteQuery(
queryAsNestedList,
queryResult,
typeString,
errorString,
correct,
evaluable,
defined,
isFunction
/*availableMemory*/);
} catch(...)
{
print("Caught exception during query execution", std::cout);
success = false;
print("errorString", errorString, std::cout);
}
print("success", success, std::cout);
print("correct", correct, std::cout);
print("evaluable", evaluable, std::cout);
print("defined", defined, std::cout);
print("isFunction", isFunction, std::cout);
return success;
}
bool SecondoUtilsLocal::adjustDatabase(const string& databaseName)
{
printFunction("SecondoUtilsLocal::adjustDatabase", std::cout);
bool success = false;
const string currentDB = SecondoSystem::GetInstance()->GetDatabaseName();
print("Current database name", currentDB, std::cout);
print("Requested database name", databaseName, std::cout);
string databaseNameUppered(databaseName);
transform(
databaseNameUppered.begin(),
databaseNameUppered.end(),
databaseNameUppered.begin(),
::toupper);
if(currentDB
!= databaseNameUppered)
{
print("Need to switch database to", databaseName, std::cout);
// Close the current database
string queryClose("close database");
success = SecondoUtilsLocal::executeQuery(queryClose);
if (!success)
{
print("Coudln't close the current database and thus couldn't \
proceed selecting the new database.", std::cout);
return false;
}
//TODO verify if database to open already exists, only create db if
// it doesn't exist.
stringstream queryCreate;
queryCreate << "create database "
<< databaseName;
success = SecondoUtilsLocal::executeQuery(queryCreate.str());
if (!success) {
print("Coudln't create database and thus couldn't select it.",
std::cout);
return false;
}
stringstream queryOpen;
queryOpen << "open database "
<< databaseName;
success = SecondoUtilsLocal::executeQuery(queryOpen.str());
} else
{
print("database name matches, no need to adjust", std::cout);
}
return success;
}
bool
SecondoUtilsLocal::createRelation(const string& queryAsString,
string& errorMessage)
{
printFunction("SecondoUtilsLocal::createRelation", std::cout);
bool correct = false;
bool evaluable = false;
bool defined = false;
bool isFunction = false;
boost::lock_guard<boost::mutex> lock(utilsMutex);
boost::lock_guard<boost::recursive_mutex> guard(nlparsemtx);
NestedList* nli = SecondoSystem::GetNestedList();
// LOG_F(INFO, "%s", "Acquiring lock for createRelation...");
// boost::lock_guard<boost::recursive_mutex> queryProcessorGuard(
// // Dereference the shared_ptr to the mutex
// *LockKeeper::getInstance()->getQueryProcessorMutex()
// );
// // Establishing a timeout for locks
// std::shared_ptr<boost::timed_mutex> qpMutex =
// LockKeeper::getInstance()->getQueryProcessorMutex();
// boost::unique_lock<boost::timed_mutex>
// queryProcessorLock{ *qpMutex, boost::try_to_lock };
// if(queryProcessorLock.owns_lock() ||
// queryProcessorLock.try_lock_for(boost::chrono::seconds{ 360 })) {
// LOG_F(INFO, "%s", "Successfully acquired QueryProcessorMutex.");
// }
// else {
// LOG_F(ERROR, "%s", "Acquisition of QueryProcessorMutex "
// "failed due to timeout.");
// return false;
// }
QueryProcessor* queryProcessor = new QueryProcessor( nli,
SecondoSystem::GetAlgebraManager(),
DEFAULT_GLOBAL_MEMORY);
//queryProcessor->SetDebugLevel(3);
SecondoCatalog* catalog = SecondoSystem::GetCatalog();
Word result = SetWord(Address(0));
OpTree tree = 0;
ListExpr resultType = nl->TheEmptyList();
print("queryAsString", queryAsString, std::cout);
SecParser secondoParser;
string queryAsNestedListString;
if (secondoParser.Text2List(queryAsString, queryAsNestedListString) != 0) {
print("could not parse query", std::cout);
return false;
}
print("query converted to nested list string", std::cout);
ListExpr queryAsNestedList;
if (!nl->ReadFromString(queryAsNestedListString, queryAsNestedList)) {
print("could not convert string to list", std::cout);
}
print("nested list string converted to nested list", std::cout);
string objectName = nl->SymbolValue(nl->Second(queryAsNestedList));
ListExpr valueExpr = nl->Fourth(queryAsNestedList);
try {
queryProcessor->Construct(valueExpr, correct, evaluable, defined,
isFunction, tree, resultType);
if (evaluable) {
string typeName = "";
catalog->CreateObject(objectName, typeName, resultType, 0);
queryProcessor->EvalS(tree, result, 1);
catalog->UpdateObject(objectName, result);
//queryProcessor->Destroy(tree, true); // > Segfault.
queryProcessor->Destroy(tree, false);
} else {
return false;
}
} catch (...) {
print("caught error", std::cout);
queryProcessor->Destroy(tree, true);
}
cout << "correct: " << correct << endl;
cout << "evaluable: " << evaluable << endl;
cout << "defined: " << defined << endl;
cout << "isFunction: " << isFunction << endl;
return true;
}
bool SecondoUtilsLocal::executeQueryCommand(const string& queryAsString)
{
printFunction("SecondoUtilsLocal::executeQueryCommand (1 arg)", std::cout);
ListExpr resultList;
string errorMessage;
bool resultOk = SecondoUtilsLocal::executeQueryCommand(
queryAsString,
resultList,
errorMessage);
if(resultOk)
{
print("query executed successfully", std::cout);
print("resultList", resultList, std::cout);
}else
{
print("failed to execute query", std::cout);
print("errorMessage", errorMessage, std::cout);
}
return resultOk;
}
bool SecondoUtilsLocal::executeQueryCommand(const string& queryAsString,
ListExpr& resultList, string& errorMessage, bool destroyRootValue) {
printFunction("SecondoUtilsLocal::executeQueryCommand (2 args)", std::cout);
bool correct = false;
bool evaluable = false;
bool defined = false;
bool isFunction = false;
print("Acquiring lock for executeQueryCommand...", std::cout);
LOG_F(INFO, "%s", "Acquiring lock for executeQueryCommand...");
boost::lock_guard<boost::mutex> lock(utilsMutex);
LOG_F(INFO, "%s", "Acquiring lock for nlparsemtx...");
boost::lock_guard<boost::recursive_mutex> guard(nlparsemtx);
LOG_F(INFO, "%s", "Successfully acquired lock for nlparsemtx...");
// boost::lock_guard<boost::recursive_mutex> queryProcessorGuard(
// // Dereference the shared_ptr to the mutex
// *LockKeeper::getInstance()->getQueryProcessorMutex()
// );
// // Establishing a timeout for locks
// std::shared_ptr<boost::timed_mutex> qpMutex =
// LockKeeper::getInstance()->getQueryProcessorMutex();
// boost::unique_lock<boost::timed_mutex>
// queryProcessorLock{ *qpMutex, boost::try_to_lock };
// if(queryProcessorLock.owns_lock() ||
// queryProcessorLock.try_lock_for(boost::chrono::seconds{ 360 })) {
// LOG_F(INFO, "%s", "Successfully acquired QueryProcessorMutex.");
// }
// else {
// LOG_F(ERROR, "%s", "Acquisition of QueryProcessorMutex "
// "failed due to timeout.");
// return false;
// }
print("Done acquiring lock for executeQueryCommand.", std::cout);
NestedList* nli = SecondoSystem::GetNestedList();
QueryProcessor* queryProcessor = new QueryProcessor( nli,
SecondoSystem::GetAlgebraManager(),
DEFAULT_GLOBAL_MEMORY);
//queryProcessor->SetDebugLevel(3);
SecondoCatalog* catalog = SecondoSystem::GetCatalog();
Word result = SetWord(Address(0));
OpTree tree = 0;
ListExpr resultType = nl->TheEmptyList();
print("queryAsString", queryAsString, std::cout);
SecParser secondoParser;
string queryAsNestedListString;
if (secondoParser.Text2List(queryAsString, queryAsNestedListString) != 0) {
print("could not parse query", std::cout);
return false;
}
print("query converted to nested list string", std::cout);
// print("queryAsNestedListString", queryAsNestedListString, std::cout);
ListExpr queryAsNestedList;
if (!nl->ReadFromString(queryAsNestedListString, queryAsNestedList)) {
print("could not convert string to list", std::cout);
}
print("nested list string converted to nested list", std::cout);
// print("queryAsNestedList", queryAsNestedList, std::cout);
try {
print("queryProcessor->Construct", std::cout);
queryProcessor->Construct(nl->Second(queryAsNestedList), correct,
evaluable, defined, isFunction, tree, resultType);
print("trying queryProcessor->Construct done", std::cout);
cout << "correct: " << correct << endl;
cout << "evaluable: " << evaluable << endl;
cout << "defined: " << defined << endl;
cout << "isFunction: " << isFunction << endl;
if (evaluable) {
queryProcessor->EvalS(tree, result, 1);
print("queryProcessor->EvalP done", std::cout);
ListExpr valueList = catalog->OutObject(resultType, result);
print("valueList done", std::cout);
resultList = nl->TwoElemList(resultType, valueList);
print("resultList done", std::cout);
// queryProcessor->Destroy(tree, true);
queryProcessor->Destroy(tree, destroyRootValue);
print("queryProcessor->Destroy done", std::cout);
}
} catch (const std::exception& e) {
print("Caught exception in SecondoUtilsLocal::executeQueryCommand: ",
string(e.what()), std::cout);
queryProcessor->Destroy(tree, false);
return false;
} catch (SI_Error errorCode) {
stringstream errorMsg;
print("Caught SI_Error in SecondoUtilsLocal::executeQueryCommand \
with code: ", errorCode, std::cout);
print("Error descriptions of SI_Error can be found in \
SecondoInterfaceGeneral.cpp.", std::cout);
errorMsg << "CSMSG: " << cmsg.getErrorMsg() << endl;
print(errorMsg.str(), std::cout);
cout << "correct: " << correct << endl;
cout << "evaluable: " << evaluable << endl;
cout << "defined: " << defined << endl;
cout << "isFunction: " << isFunction << endl;
//queryProcessor->Destroy(tree, true);
queryProcessor->Destroy(tree, false);
return false;
} catch (...) {
print("Caught unknown exception in \
SecondoUtilsLocal::executeQueryCommand.", std::cout);
//queryProcessor->Destroy(tree, true);
queryProcessor->Destroy(tree, false);
return false;
}
return true;
}
bool SecondoUtilsLocal::lookupDBServiceLocation(
string& host,
string& commPort)
{
printFunction("DBServiceConnector::lookupDBServiceLocation", std::cout);
SecondoUtilsLocal::readFromConfigFile(host,
"DBService",
"DBServiceHost",
"");
if(host.length() == 0)
{
print("could not find DBServiceHost in config file", std::cout);
return false;
}
SecondoUtilsLocal::readFromConfigFile(commPort,
"DBService",
"DBServicePort",
"");
if(commPort.length() == 0)
{
print("could not find DBServicePort in config file", std::cout);
return false;
}
return true;
}
boost::mutex SecondoUtilsLocal::utilsMutex;
} /* namespace DBService */