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

1781 lines
50 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2015,
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 "ConnectionInfo.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "Timeout.h"
#include "Dist2Helper.h"
#include "FileSystem.h"
#include "FileRelations.h"
#include "FileAttribute.h"
extern boost::recursive_mutex nlparsemtx;
boost::mutex createRelMut;
boost::mutex copylistmutex;
extern NestedList* nl;
namespace distributed2
{
/*
1.1 Constructor
Creates a new connection instance.
*/
ConnectionInfo::ConnectionInfo(const std::string& _host,
const int _port,
const std::string& _config,
SecondoInterfaceCS* _si,
NestedList* _mynl,
const size_t timeout,
const int heartbeat) :
host(_host), port(_port), config(_config), si(_si)
{
mynl = _mynl;
secondoHome = "";
requestFolder = "";
requestPath = "";
sendFolder = "";
sendPath = "";
serverPID=0;
num = -1;
cmdLog = 0;
noReferences = 1;
guard_type guard(simtx);
tonotifier = new TimeoutNotifier<ConnectionInfo>(this);
hbobserver = new HeartbeatObserver<ConnectionInfo>(this);
if(si!=0){
si->setHeartbeat(heartbeat,heartbeat);
si->addMessageHandler(hbobserver);
try{
if(timeout>0){
startTimeout(timeout,false);
}
serverPID = si->getPid();
secondoHome = si->getHome();
sendFolder = si->getSendFileFolder();
requestFolder = si->getRequestFileFolder();
requestPath = si->getRequestFilePath();
sendPath = si->getSendFilePath();
std::cerr << "Created a new connection to " << host << ":"
<< port << " (PID: " << serverPID << ")" << std::endl;
if(timeout>0){
stopTimeout(false);
}
} catch(...){
std::cerr << " Problem in ConnectionInfo constructor" << endl;
if(timeout>0){
stopTimeout(false);
}
}
}
}
bool ConnectionInfo::reconnect(bool showCommands, CommandLog& log,
const size_t timeout,
const int heartbeat){
//cout << "try to reconnect " << host <<":" << port << endl;
guard_type guard(simtx);
si->removeMessageHandler(hbobserver);
try{
this->si->Terminate();
} catch(...) {
std::cerr << "reconnect: Exception during terminate" << endl;
}
try{
delete this->si;
} catch(...) {
std::cerr << "reconnect: Exception during deletion of si " << endl;
}
si = new SecondoInterfaceCS(true, mynl, true);
si->addMessageHandler(hbobserver);
std::string user = "";
std::string passwd = "";
std::string errMsg;
si->setMaxAttempts(4);
si->setTimeout(2);
if (!si->Initialize(user, passwd, host, stringutils::int2str(port), config,
"",errMsg, true)) {
std::cerr << "reconnect: Initialisation of newly created "
"secondoInterface failed" << endl;
std::cerr << "Error : " << errMsg << endl;
return false;
}
if(si!=0){
try{
if(timeout>0){
startTimeout(timeout,false);
}
serverPID = si->getPid();
switchDatabase(SecondoSystem::GetInstance()->GetDatabaseName(),
true, false, true, timeout);
retrieveSecondoHome(showCommands,log);
si->setHeartbeat(heartbeat, heartbeat);
if(timeout>0){
stopTimeout(false);
}
} catch(...){
std::cerr << "error during collecting standard information" << endl;
if(timeout>0){
stopTimeout(false);
}
return false;
}
}
return si!=0;
}
/*
1.2 Destructor
Terminates the connection and destroys the object.
*/
ConnectionInfo::~ConnectionInfo()
{
//cout << "Destroy connectionInfo" << endl;
try
{
guard_type guard(simtx);
si->Terminate();
}
catch(...) {}
delete si;
si = 0;
delete mynl;
delete hbobserver;
delete tonotifier;
}
void ConnectionInfo::deleteIfAllowed() {
norefmtx.lock();
assert(noReferences>0);
noReferences--;
if(noReferences==0){
norefmtx.unlock();
delete this;
} else {
norefmtx.unlock();
}
}
/*
1.3 ~getHost~
returns the remote host.
*/
std::string ConnectionInfo::getHost() const
{
return host;
}
/*
1.4 getPort
*/
int ConnectionInfo::getPort() const
{
return port;
}
/*
1.5 getConfig
Returns the configuration file used for the client.
Has nothing to do with the configuration file used by the
remove monitor.
*/
std::string ConnectionInfo::getConfig() const
{
return config;
}
/*
1.6 check
Checks whether the remote server is working by sending a simple command.
Here, the command is always executed even if the command logger is not null.
*/
bool ConnectionInfo::check(bool showCommands,
CommandLog& commandLog,
const size_t timeout)
{
ListExpr res;
std::string cmd = "list databases";
SecErrInfo err;
{
guard_type guard(simtx);
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(timeout>0){
startTimeout(timeout,true);
}
si->Secondo(cmd, res, err);
if(err.code){
//cerr << "Secondo function used during check() returns an error"
// << endl;
//cerr << "Code is " << err.code << endl;
//cerr << "This means " << err.msg << endl;
return false;
}
double rt = sw.diffSecondsReal();
std::string home = this->getSecondoHome(showCommands, commandLog);
commandLog.insert(this, this->getHost(),
home,
cmd, rt, err.code);
showCommand(si, host, port, cmd, false, showCommands);
if(timeout>0){
stopTimeout(true);
}
}
return err.code == 0;
}
/*
1.7 setId
Sets the id.
*/
void ConnectionInfo::setId(const int i)
{
guard_type guard(simtx);
if (si) {
si->setId(i);
}
}
/*
1.8 simpleCommand
Performs a command on the remote server. The result is stored as a string.
*/
void ConnectionInfo::simpleCommand(std::string command1,
int& err,
std::string& result,
bool rewrite,
double& runtime,
bool showCommands,
CommandLog& commandLog,
bool forceExec /*=false*/,
const size_t timeout /*=0*/)
{
std::string command;
if (rewrite)
{
rewriteQuery(command1, command);
} else
{
command = command1;
}
SecErrInfo serr;
ListExpr resList;
{
guard_type guard(simtx);
StopWatch sw;
showCommand(si, host, port, command, true, showCommands);
if(!cmdLog || forceExec){
if(timeout>0){
startTimeout(timeout,true);
}
si->Secondo(command, resList, serr);
if(timeout>0){
stopTimeout(true);
}
} else {
cmdLog->insert(this, command);
serr.code = 0;
serr.msg = "command not evaluated";
resList = mynl->TheEmptyList();
}
showCommand(si, host, port, command, false, showCommands);
runtime = sw.diffSecondsReal();
err = serr.code;
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog),
command, runtime, err);
if (err == 0)
{
result = mynl->ToString(resList);
} else
{
result = si->GetErrorMessage(err);
}
}
}
/*
1.9 getSecondoHome
Returns the path of the secondo databases of the remote server.
*/
std::string ConnectionInfo::getSecondoHome(bool showCommands,
CommandLog& commandLog)
{
return secondoHome;
}
/*
1.10 cleanUp
This command removes temporal objects on the remote server.
Such objects having names starting with TMP[_]. Furthermore,
files starting with TMP are removed within the dfarray directory
of the remote server.
*/
bool ConnectionInfo::cleanUp(bool showCommands,
CommandLog& commandLog,
const size_t timeout)
{
guard_type guard(simtx);
// first step : remove database objects
std::string command = "query getcatalog() "
"filter[.ObjectName startsWith \"TMP_\"] "
"extend[OK : deleteObject(.ObjectName)] "
" count";
int err;
std::string res;
double rt;
simpleCommand(command, err, res, false, rt, showCommands,
commandLog, false,timeout);
bool result = err == 0;
std::string dbname = SecondoSystem::GetInstance()->GetDatabaseName();
std::string path = getSecondoHome(showCommands, commandLog)
+ "/dfarrays/" + dbname + "/";
command = "query getDirectory('" + path + "') "
"filter[basename(.) startsWith \"TMP_\"] "
"namedtransformstream[F] "
"extend[ OK : removeDirectory(.F, TRUE)] count";
simpleCommand(command, err, res, false, rt, showCommands,
commandLog, false, timeout);
result = result && (err == 0);
return result;
}
bool ConnectionInfo::cleanUp1(const size_t timeout) {
static CommandLog log;
return cleanUp(false,log, timeout);
}
/*
1.11 switchDatabase
Switches the remote server to another database.
*/
bool ConnectionInfo::switchDatabase(const std::string& dbname,
bool createifnotexists,
bool showCommands,
bool forceExec,
const size_t timeout)
{
guard_type guard(simtx);
// close database ignore errors
SecErrInfo serr;
ListExpr resList;
std::string cmd = "close database";
showCommand(si, host, port, cmd, true, showCommands);
if(timeout>0){
startTimeout(timeout,false);
}
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
showCommand(si, host, port, cmd, false, showCommands);
// create database ignore errors
if (createifnotexists)
{
cmd = "create database " + dbname;
showCommand(si, host, port, cmd, true, showCommands);
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
showCommand(si, host, port, cmd, false, showCommands);
}
// open database
cmd = "open database " + dbname;
showCommand(si, host, port, cmd, true, showCommands);
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
showCommand(si, host, port, cmd, false, showCommands);
bool res = serr.code == 0;
if(timeout>0){
stopTimeout(false);
}
activeDatabase = dbname;
return res;
}
/*
1.12 simpleCommand
This variant of ~simpleCommand~ returns the result as a list.
*/
void ConnectionInfo::simpleCommand(const std::string& command1,
int& error,
std::string& errMsg,
std::string& resList,
const bool rewrite,
double& runtime,
bool showCommands,
CommandLog& commandLog,
bool forceExec,
const size_t timeout)
{
std::string command;
if (rewrite)
{
rewriteQuery(command1, command);
} else
{
command = command1;
}
{
guard_type guard(simtx);
if(timeout>0){
startTimeout(timeout,true);
}
SecErrInfo serr;
ListExpr myResList = mynl->TheEmptyList();
StopWatch sw;
showCommand(si, host, port, command, true, showCommands);
if(!cmdLog || forceExec){
si->Secondo(command, myResList, serr);
} else {
cmdLog->insert(this, command);
myResList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
if(timeout>0){
stopTimeout(true);
}
showCommand(si, host, port, command, false, showCommands);
runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog),
command, runtime, serr.code);
error = serr.code;
errMsg = serr.msg;
resList = mynl->ToString(myResList);
mynl->Destroy(myResList);
}
}
/*
1.13 simpleCommandFromList
Performs a command that is given in nested list format.
*/
void ConnectionInfo::simpleCommandFromList(const std::string& command1,
int& error,
std::string& errMsg,
std::string& resList,
const bool rewrite,
double& runtime,
bool showCommands,
CommandLog& commandLog,
bool forceExec,
int timeout)
{
guard_type guard(simtx);
if(timeout>0){
startTimeout(timeout,true);
}
try{
std::string command;
if (rewrite)
{
rewriteQuery(command1, command);
} else
{
command = command1;
}
ListExpr cmd = mynl->TheEmptyList();
{
boost::lock_guard<boost::recursive_mutex> guard(nlparsemtx);
if (!mynl->ReadFromString(command, cmd))
{
error = 3;
errMsg = "error in parsing list";
return;
}
}
SecErrInfo serr;
ListExpr myResList = mynl->TheEmptyList();
StopWatch sw;
showCommand(si, host, port, command, true, showCommands);
if(!cmdLog || forceExec){
si->Secondo(cmd, myResList, serr);
} else {
cmdLog->insert(this, mynl->ToString(cmd));
myResList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
if(serr.code != 0){
std::cerr << "error during secondo command" << endl;
std::cerr << "code : " << serr.code << endl;
std::cerr << "msg : " << serr.msg << endl;
}
showCommand(si, host, port, command, false, showCommands);
runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog),
command, runtime, serr.code);
error = serr.code;
errMsg = serr.msg;
resList = mynl->ToString(myResList);
if (mynl->AtomType(cmd) != NoAtom && !mynl->IsEmpty(cmd))
{
mynl->Destroy(cmd);
}
if (mynl->AtomType(myResList) != NoAtom && !mynl->IsEmpty(myResList))
{
mynl->Destroy(myResList);
}
} catch(...){
std::cerr << "Exception during simpleCommandFromList " << endl;
}
if(timeout>0){
stopTimeout(true);
}
}
/*
1.13 simpleCommand
This variant provides the result as a list.
*/
void ConnectionInfo::simpleCommand(const std::string& command1,
int& error,
std::string& errMsg,
ListExpr& resList,
const bool rewrite,
double& runtime,
bool showCommands,
CommandLog& commandLog,
bool forceExec,
const size_t timeout)
{
std::string command;
if (rewrite)
{
rewriteQuery(command1, command);
} else
{
command = command1;
}
guard_type guard(simtx);
if(timeout>0){
startTimeout(timeout,true);
}
SecErrInfo serr;
ListExpr myResList = mynl->TheEmptyList();
StopWatch sw;
showCommand(si, host, port, command, true, showCommands);
if(!cmdLog || forceExec){
si->Secondo(command, myResList, serr);
} else {
cmdLog->insert(this, command);
myResList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
if(timeout>0){
stopTimeout(true);
}
showCommand(si, host, port, command, false, showCommands);
runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog),
command, runtime, serr.code);
error = serr.code;
errMsg = serr.msg;
if(nl!=mynl){
// copy resultlist from local nested list to global nested list
boost::lock_guard < boost::mutex > guard(copylistmutex);
resList = mynl->CopyList(myResList, nl);
mynl->Destroy(myResList);
} else {
resList = myResList;
}
}
/*
1.14 serverPid
returns the process id of the remote server
*/
int ConnectionInfo::serverPid()
{
return serverPID;
}
/*
1.15 sendFile
transfers a locally stored file to the remote server.
It returns an error code.
*/
int ConnectionInfo::sendFile(const std::string& local,
const std::string& remote,
const bool allowOverwrite,
const size_t timeout)
{
guard_type guard(simtx);
if(timeout>0){
startTimeout(timeout,false);
}
int res = si->sendFile(local, remote, allowOverwrite);
if(timeout>0){
stopTimeout(false);
}
return res;
}
/*
1.16 requestFile
Transfers a remotely stored file to the local file system.
*/
int ConnectionInfo::requestFile(const std::string& remote,
const std::string& local,
const bool allowOverwrite,
const size_t timeout)
{
guard_type guard(simtx);
if(timeout>0){
startTimeout(timeout,false);
}
int res = si->requestFile(remote, local, allowOverwrite);
if(timeout>0){
stopTimeout(false);
}
return res;
}
/*
1.17 getRequestFolder
Returns the path on remote machine for requesting files.
*/
std::string ConnectionInfo::getRequestFolder()
{
return requestFolder;
}
std::string ConnectionInfo::getRequestPath(){
return requestPath;
}
/*
1.18 getSendFolder
returns the folder the remote machine where files are stored.
This folder is a subdirectory of the request folder.
*/
std::string ConnectionInfo::getSendFolder()
{
return sendFolder;
}
/*
1.19 getSendPath
Returns the complete path where files are stored.
*/
std::string ConnectionInfo::getSendPath()
{
return sendPath;
}
/*
1.20 Factory function
*/
ConnectionInfo* ConnectionInfo::createConnection(const std::string& host,
const int port,
std::string& config,
const size_t timeout,
const int heartbeat)
{
NestedList* mynl = new NestedList("temp_nested_list_"
+ std::to_string(port));
SecondoInterfaceCS* si = new SecondoInterfaceCS(true, mynl, true);
std::string user = "";
std::string passwd = "";
std::string errMsg;
si->setMaxAttempts(4);
si->setTimeout(1);
if (!si->Initialize(user, passwd, host, stringutils::int2str(port), config,
"",errMsg, true))
{
delete si;
si = 0;
delete mynl;
return 0;
} else
{
return new ConnectionInfo(host, port, config, si, mynl,
timeout, heartbeat);
}
}
/*
1.21 createOrUpdateObject
creates a new object or updates an existing one on remote server.
*/
bool ConnectionInfo::createOrUpdateObject(const std::string& name,
ListExpr typelist,
Word& value,
bool showCommands,
CommandLog& commandLog,
bool forceExec,
const size_t timeout)
{
if (Relation::checkType(typelist))
{
return createOrUpdateRelation(name, typelist, value,
showCommands, commandLog,
forceExec,
timeout);
}
guard_type guard(simtx);
SecErrInfo serr;
ListExpr resList;
std::string cmd = "delete " + name;
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(timeout>0){
startTimeout(timeout,false);
}
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
double runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
// ignore error (object must not exist)
std::string filename = name + "_" + stringutils::int2str(WinUnix::getpid())
+ ".obj";
storeObjectToFile(name, value, typelist, filename);
cmd = "restore " + name + " from '" + filename + "'";
showCommand(si, host, port, cmd, true, showCommands);
sw.start();
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
FileSystem::DeleteFileOrFolder(filename);
if(timeout>0){
stopTimeout(false);
}
return serr.code == 0;
}
/*
1.22 createOrUpdateRelation
Accelerated version for relations.
*/
bool ConnectionInfo::createOrUpdateRelation(const std::string& name,
ListExpr typeList,
Word& value,
bool showCommands,
CommandLog& commandLog,
bool forceExec,
const size_t timeout)
{
//guard_type guard(simtx);
// write relation to a file
std::string filename = name + "_" + stringutils::int2str(WinUnix::getpid())
+ ".bin";
if (!saveRelationToFile(typeList, value, filename))
{
return false;
}
// restore remote relation from local file
bool ok = createOrUpdateRelationFromBinFile(name, filename,
showCommands, commandLog,
true,
forceExec, timeout);
// remove temporarly file
FileSystem::DeleteFileOrFolder(filename);
return ok;
}
/*
1.23 createOrUpdateRelationFromBinFile
Creates a new relation or updates an existing one on remote server from
local file.
*/
bool ConnectionInfo::createOrUpdateRelationFromBinFile(const std::string& name,
const std::string& filename,
bool showCommands,
CommandLog& commandLog,
const bool allowOverwrite,
bool forceExec,
const size_t timeout)
{
guard_type guard(simtx);
if(timeout>0){
startTimeout(timeout,false);
}
SecErrInfo serr;
ListExpr resList;
// transfer file to remote server
int error = si->sendFile(filename, filename, true);
if (error != 0)
{
if(timeout>0){
stopTimeout(false);
}
std::cerr << "error during transfer file " << filename
<< "from master to " << (*this) << std::endl;
return false;
}
// retrieve folder from which the filename can be read
std::string sendFolder = sendPath;
std::string rfilename = sendFolder + "/" + filename;
// delete existing object
std::string cmd = "delete " + name;
if (allowOverwrite)
{
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
double runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog),
cmd, runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
}
cmd = "let " + name + " = '" + rfilename + "' ffeed5 consume ";
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
double runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
bool ok = serr.code == 0;
if(!ok){
std::cerr << "error during creation of a relation from local file "
<< filename << std::endl;
std::cerr << "ErrorCode :" << serr.code << std::endl;
std::cerr << "ErrorMessage : " << serr.msg << std::endl;
std::cerr << "Command :" << std::endl << cmd << std::endl;
}
cmd = "query removeFile('" + rfilename + "')";
sw.start();
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
if(timeout>0){
stopTimeout(false);
}
return ok;
}
/*
1.24 createOrUpdateAttributeFromBinFile
Creates an new attribute object or updates an existing one on remote server
from a local file.
*/
bool ConnectionInfo::createOrUpdateAttributeFromBinFile(const std::string& name,
const std::string& filename,
bool showCommands,
CommandLog& commandLog,
const bool allowOverwrite,
bool forceExec,
const size_t timeout)
{
guard_type guard(simtx);
if(timeout>0){
startTimeout(timeout,false);
}
SecErrInfo serr;
ListExpr resList;
// transfer file to remote server
int error = si->sendFile(filename, filename, true);
if (error != 0)
{
if(timeout>0){
stopTimeout(false);
}
return false;
}
// retrieve folder from which the filename can be read
std::string sendFolder = sendPath;
std::string rfilename = sendFolder + "/" + filename;
// delete existing object
std::string cmd = "delete " + name;
if (allowOverwrite)
{
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
double runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog),
cmd, runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
}
cmd = "let " + name + " = loadAttr('" + rfilename + "') ";
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
double runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
bool ok = serr.code == 0;
cmd = "query removeFile('" + rfilename + "')";
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
if(timeout>0){
stopTimeout(false);
}
return ok;
}
/*
1.26 saveRelationToFile
Stores a local relation info a binary local file.
*/
bool ConnectionInfo::saveRelationToFile(ListExpr relType,
Word& value,
const std::string& filename)
{
BinRelWriter brw(filename, relType, FILE_BUFFER_SIZE);
if(!brw.ok()){
return false;
}
Relation* rel = (Relation*) value.addr;
GenericRelationIterator* it = rel->MakeScan();
bool ok = true;
Tuple* tuple = 0;
while (ok && ((tuple = it->GetNextTuple()) != 0))
{
ok = brw.writeNextTuple(tuple);
tuple->DeleteIfAllowed();
}
delete it;
return ok;
}
/*
1.27 saveAttributeToFile
saves an attribute to a local file.
*/
bool ConnectionInfo::saveAttributeToFile(ListExpr type,
Word& value,
const std::string& filename)
{
Attribute* attr = (Attribute*) value.addr;
return FileAttribute::saveAttribute(type, attr, filename);
}
/*
1.28 storeObjectToFile
Stores any object to a file using its nested list represnetation.
*/
bool ConnectionInfo::storeObjectToFile(const std::string& objName,
Word& value,
ListExpr typeList,
const std::string& fileName)
{
SecondoCatalog* ctl = SecondoSystem::GetCatalog();
ListExpr valueList = ctl->OutObject(typeList, value);
ListExpr objList = nl->FiveElemList(nl->SymbolAtom("OBJECT"),
nl->SymbolAtom(objName),
nl->TheEmptyList(), typeList,
valueList);
return nl->WriteToFile(fileName, objList);
}
/*
1.29 retrieve
Retrieves a remote object.
*/
bool ConnectionInfo::retrieve(const std::string& objName,
ListExpr& resType,
Word& result,
bool checkType,
bool showCommands,
CommandLog& commandLog,
int fileIndex,
bool forceExec,
const size_t timeout)
{
//cout << "retrieve" << endl;
//cout << "objName = " << objName << endl;
//cout << "resType = " << nl->ToString(resType) << endl;
//cout << "checkType = " << checkType << endl;
//cout << "fileIndex = " << fileIndex << endl;
if (Relation::checkType(resType))
{
if (retrieveRelation(objName, resType, result,
showCommands, commandLog, fileIndex,
false, timeout))
{
return true;
}
std::cerr << "Could not use fast retrieval for a relation, failback"
<< endl;
}
{
guard_type guard(simtx);
if(timeout>0){
startTimeout(timeout,false);
}
SecErrInfo serr;
ListExpr myResList;
std::string cmd = "query " + objName;
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(!cmdLog || forceExec){
si->Secondo(cmd, myResList, serr);
} else {
cmdLog->insert(this, cmd);
myResList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
if(timeout>0){
stopTimeout(false);
}
double runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
SecondoCatalog* ctlg = SecondoSystem::GetCatalog();
if (serr.code != 0)
{
return false;
}
if (!mynl->HasLength(myResList, 2))
{
return false;
}
// copy result list into global list memory
ListExpr resList;
{
boost::lock_guard < boost::mutex > guard(copylistmutex);
resList = mynl->CopyList(myResList, nl);
mynl->Destroy(myResList);
}
ListExpr resType2 = nl->First(resList);
if (checkType && !nl->Equal(resType, resType2))
{
// other type than expected
return false;
}
ListExpr value = nl->Second(resList);
int errorPos = 0;
ListExpr errorInfo = listutils::emptyErrorInfo();
bool correct;
{
boost::lock_guard < boost::mutex > guard(createRelMut);
result = ctlg->InObject(resType, value, errorPos, errorInfo, correct);
}
if (!correct)
{
result.addr = 0;
}
return correct;
}
}
/*
1.30 retrieveRelation
Special accelerated version for relations
*/
bool ConnectionInfo::retrieveRelation(const std::string& objName,
ListExpr& resType,
Word& result,
bool showCommands,
CommandLog& commandLog,
const int fileIndex,
bool forceExec,
const size_t timeout)
{
//guard_type guard(simtx);
std::string fi = stringutils::int2str(fileIndex);
std::string fname1 = objName + "_" + fi + ".bin";
if (!retrieveRelationFile(objName, fname1, showCommands,
commandLog, forceExec,timeout))
{
return false;
}
result = createRelationFromFile(fname1, resType);
FileSystem::DeleteFileOrFolder(fname1);
return true;
}
/*
1.31 retrieveRelationInFile
Retrieves a relation which is on a remotely stored file.
*/
bool ConnectionInfo::retrieveRelationInFile(const std::string& fileName,
ListExpr& resType,
Word& result,
bool showCommands,
CommandLog& commandLog,
bool forceExec,
const size_t timeout)
{
guard_type guard(simtx);
result.addr = 0;
// get the full path for requesting files
std::string rfpath;
try{
rfpath = requestPath + "/";
} catch(...){
return false;
}
std::string base = FileSystem::Basename(fileName);
if (stringutils::startsWith(fileName, rfpath))
{
if(timeout>0){
startTimeout(timeout,false);
}
bool ok = si->requestFile(fileName.substr(rfpath.length()),
base + ".tmp",
true);
if(timeout>0){
stopTimeout(false);
}
// we can just get the file without copying it
if (!ok) {
return false;
}
result = createRelationFromFile(base + ".tmp", resType);
FileSystem::DeleteFileOrFolder(base + ".tmp");
return true;
}
// remote file located in a not accessible folder, send command
// to copy it into a such folder
std::string cmd = "query copyFile('" + fileName + "', '" + rfpath + base
+ ".tmp')";
SecErrInfo serr;
ListExpr resList;
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(timeout>0){
startTimeout(timeout,false);
}
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
if(timeout>0){
stopTimeout(false);
}
double runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
if (serr.code != 0)
{
showError(si, cmd, serr.code, serr.msg);
return false;
}
if (!mynl->HasLength(resList, 2)
|| mynl->AtomType(mynl->Second(resList)) != BoolType)
{
std::cerr << "command " << cmd << " returns unexpected result" << endl;
std::cerr << mynl->ToString(resList) << endl;
return false;
}
if (!mynl->BoolValue(mynl->Second(resList)))
{
mynl->Destroy(resList);
return false;
}
mynl->Destroy(resList);
// copy the file to local file system
if (si->requestFile(base + ".tmp", base + ".tmp", true) != 0)
{
std::cerr << "Requesting file " + base + ".tmp failed" << endl;
return false;
}
result = createRelationFromFile(base + ".tmp", resType);
FileSystem::DeleteFileOrFolder(base + ".tmp");
cmd = "query removeFile('" + rfpath + base + ".tmp' )";
showCommand(si, host, port, cmd, true, showCommands);
sw.start();
if(timeout>0){
startTimeout(timeout,true);
}
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
if(timeout>0){
stopTimeout(false);
}
runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
if (serr.code != 0)
{
showError(si, cmd, serr.code, serr.msg);
}
return true;
}
/*
1.32 retrieveRelationFile
retrieves a remote relation and stored it into a local file.
*/
bool ConnectionInfo::retrieveRelationFile(const std::string& objName,
const std::string& fname1,
bool showCommands,
CommandLog& commandLog,
bool forceExec,
const size_t timeout)
{
guard_type guard(simtx);
std::string rfname;
try{
rfname = requestPath + "/" + fname1;
} catch(...){
return false;
}
// save the remove relation into a binary file
SecErrInfo serr;
ListExpr resList;
std::string cmd = "query createDirectory('" + requestPath
+ "', TRUE) ";
showCommand(si, host, port, cmd, true, showCommands);
StopWatch sw;
if(timeout>0){
startTimeout(timeout,false);
}
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
double runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
if (serr.code != 0)
{
std::cerr << "Creating filetransfer directory failed" << endl;
std::cerr << "serr.code = " << serr.code << endl;
std::cerr << "serr.Msg = " << serr.msg << endl;
if(timeout>0){
stopTimeout(false);
}
return false;
}
cmd = "query " + objName + " feed fconsume5['" + rfname + "'] count";
showCommand(si, host, port, cmd, true, showCommands);
sw.start();
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
if (serr.code != 0)
{
if(timeout>0){
stopTimeout(false);
}
return false;
}
if (si->requestFile(fname1, fname1, true) != 0)
{
return false;
}
// delete remote file
cmd = "query removeFile('" + rfname + "')";
showCommand(si, host, port, cmd, true, showCommands);
sw.start();
if(!cmdLog || forceExec){
si->Secondo(cmd, resList, serr);
} else {
cmdLog->insert(this, cmd);
resList = mynl->TheEmptyList();
serr.code = 0;
serr.msg = "command not executed";
}
runtime = sw.diffSecondsReal();
commandLog.insert(this, this->getHost(),
this->getSecondoHome(showCommands, commandLog), cmd,
runtime, serr.code);
showCommand(si, host, port, cmd, false, showCommands);
if(timeout>0){
stopTimeout(false);
}
return true;
}
/*
1.34 retrieveAnyFile
This function can be used to get any file from a remote server
even if the file is located outside the requestFile directory.
*/
bool ConnectionInfo::retrieveAnyFile(const std::string& remoteName,
const std::string& localName,
bool showCommands,
CommandLog& commandLog,
bool forceExec,
const size_t timeout)
{
guard_type guard(simtx);
std::string rf = getRequestFolder();
bool copyRequired = !stringutils::startsWith(remoteName, rf);
std::string cn;
int err;
std::string errMsg;
ListExpr result;
double rt;
if (!copyRequired)
{
cn = remoteName;
} else
{
// create request dir
std::string cmd = "query createDirectory('" + rf + "', TRUE)";
simpleCommand(cmd, err, errMsg, result, false, rt,
showCommands, commandLog, forceExec, timeout);
if (err)
{
showError(this, cmd, err, errMsg);
return false;
}
cn = "tmp_" + stringutils::int2str(serverPid()) + "_"
+ FileSystem::Basename(remoteName);
std::string cf = getSecondoHome(showCommands, commandLog)
+ "/" + rf + "/" + cn;
cmd = "query copyFile('" + remoteName + "','" + cf + "')";
simpleCommand(cmd, err, errMsg, result, false, rt, showCommands,
commandLog, forceExec, timeout);
if (err)
{
std::cerr << "command " << cmd << " failed" << endl;
return false;
}
if (!nl->HasLength(result, 2))
{
std::cerr << "unexpected result for command " << cmd << endl;
std::cerr << "expected (type value), got " << nl->ToString(result)
<< endl;
return false;
}
if (nl->AtomType(nl->Second(result)) != BoolType)
{
std::cerr << "unexpected result for command " << cmd << endl;
std::cerr << "expected (bool boolatom), got "
<< nl->ToString(result) << endl;
return false;
}
if (!nl->BoolValue(nl->Second(result)))
{
std::cerr << "copying file failed" << endl;
if(true) {
cout << "remote Server : " << (*this) << endl;
cout << "command " << endl << cmd << endl;
cout << "returned false" << endl;
}
return false;
}
}
int errres = requestFile(cn, localName, true, timeout);
if (copyRequired)
{
// remove copy
std::string cmd = "query removeFile('" + cn + "')";
simpleCommand(cmd, err, errMsg, result, false, rt, showCommands,
commandLog, forceExec, timeout);
if (err)
{
std::cerr << "command " << cmd << " failed" << endl;
}
}
return errres == 0;
}
/*
1.35 creates a relation from its binary file representation.
*/
Word ConnectionInfo::createRelationFromFile(const std::string& fname,
ListExpr& resType)
{
// guard_type guard(simtx);
Word result((void*) 0);
// create result relation
ListExpr tType = nl->Second(resType);
tType = SecondoSystem::GetCatalog()->NumericType(resType);
TupleType* tt = new TupleType(nl->Second(tType));
ffeed5Info reader(fname, tt);
if (!reader.isOK())
{
tt->DeleteIfAllowed();
return result;
}
ListExpr typeInFile = reader.getRelType();
if (!nl->Equal(resType, typeInFile))
{
std::cerr << "Type conflict between expected type and type in file"
<< endl
<< "Expected : " << nl->ToString(resType) << endl
<< "Type in File " << nl->ToString(typeInFile) << endl;
tt->DeleteIfAllowed();
return result;
}
Relation* resultrel;
{
boost::lock_guard < boost::mutex > guard2(createRelMut);
resultrel = new Relation(tType);
}
Tuple* tuple;
while ((tuple = reader.next()))
{
boost::lock_guard < boost::mutex > guard2(createRelMut);
resultrel->AppendTuple(tuple);
tuple->DeleteIfAllowed();
}
tt->DeleteIfAllowed();
result.addr = resultrel;
return result;
}
std::ostream& ConnectionInfo::print(std::ostream& o) const
{
o << host << ", " << port << ", " << config;
return o;
}
// retrieves secondoHome from remote server
void ConnectionInfo::retrieveSecondoHome(bool showCommands,
CommandLog& commandLog)
{
guard_type guard(simtx);
secondoHome = si?si->getHome():"";
}
void ConnectionInfo::retrieveSecondoHome()
{
guard_type guard(simtx);
secondoHome = si?si->getHome():"";
}
void ConnectionInfo::killConnection(){
if(si){
si->killConnection();
}
}
void ConnectionInfo::timeout(){
std::cout << "received timeout signal" << endl;
killConnection();
}
void ConnectionInfo::startTimeout(int second, bool withMessages){
if(withMessages){
hbobserver->stop();
hbobserver->start(second);
} else {
tonotifier->stop();
tonotifier->start(second);
}
}
void ConnectionInfo::stopTimeout(const bool msg){
if(msg){
hbobserver->stop();
} else {
tonotifier->stop();
}
}
std::ostream& operator<<(std::ostream& o, const ConnectionInfo& sc)
{
return sc.print(o);
}
void showError(const ConnectionInfo* ci, const std::string& command ,
const int errorCode, const std::string& errorMessage){
static boost::mutex mtx;
boost::lock_guard<boost::mutex> lock(mtx);
if(errorCode){
std::cerr << "command " << command << endl
<< " failed on server " << (*ci) << endl
<< "with code " << errorCode << " : " << errorMessage << endl;
}
}
void showError(const SecondoInterfaceCS* ci, const std::string& command ,
const int errorCode, const std::string& errorMessage){
static boost::mutex mtx;
boost::lock_guard<boost::mutex> lock(mtx);
if(errorCode){
std::cerr << "command " << command << endl
<< " failed on server " << (ci->getHost()) << endl
<< "with code " << errorCode << " : " << errorMessage << endl;
}
}
}/* namespace distributed2 */