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

405 lines
10 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 "Algebras/DBService2/Node.hpp"
#include "Algebras/DBService2/Query.hpp"
#include "Algebras/DBService2/SecondoNodeAdapter.hpp"
#include <string>
#include <sstream>
#include <loguru.hpp>
using namespace std;
namespace DBService {
/*
TODO Implement Node updates.
*/
Node::Node() : Record::Record()
{
setHost("");
setPort(0);
setConfig("");
setDiskPath("");
setComPort(0);
setTransferPort(0);
setType(Node::nodeTypeDBService());
}
Node::Node(const string newHost,
const int newPort,
string newConfig) : Record::Record()
{
setHost(newHost);
setPort(newPort);
setConfig(newConfig);
setDiskPath("");
setComPort(0);
setTransferPort(0);
setType(Node::nodeTypeDBService());
}
Node::Node(const string newHost,
const int newPort,
string newConfig, string newDiskPath, int newComPort,
int newTransferPort) : Record::Record()
{
setHost(newHost);
setPort(newPort);
setConfig(newConfig);
setDiskPath(newDiskPath);
setComPort(newComPort);
setTransferPort(newTransferPort);
setType(Node::nodeTypeDBService());
}
Node::Node(const Host newHost,
const int newPort,
string newConfig, string newDiskPath, int newComPort,
int newTransferPort) : Record::Record()
{
setHost(newHost);
setPort(newPort);
setConfig(newConfig);
setDiskPath(newDiskPath);
setComPort(newComPort);
setTransferPort(newTransferPort);
setType(Node::nodeTypeDBService());
}
Node::Node(const Node &original) : Record(original) {
setHost(original.getHost());
setPort(original.getPort());
setConfig(original.getConfig());
setDiskPath(original.getDiskPath());
setComPort(original.getComPort());
setTransferPort(original.getTransferPort());
setType(Node::nodeTypeDBService());
setDatabase(original.getDatabase());
}
Node::Node(Node &&original) : Record(original) {
setHost(original.getHost());
setPort(original.getPort());
setConfig(original.getConfig());
setDiskPath(original.getDiskPath());
setComPort(original.getComPort());
setTransferPort(original.getTransferPort());
setType(Node::nodeTypeDBService());
setDatabase(original.getDatabase());
}
string Node::getRelationName() {
return "dbs_nodes";
}
string Node::getType() const {
return type;
}
void Node::setType(string newType) {
if (newType != getType()) {
if (getIsNew() == true) {
type = newType;
} else {
throw "Can't change the type of a non-new record.";
}
}
}
Host Node::getHost() const {
return host;
}
string Node::getConfig() const {
return config;
}
int Node::getPort() const {
return port;
}
string Node::getDiskPath() const
{
return diskPath;
}
int Node::getComPort() const
{
return comPort;
}
int Node::getTransferPort() const
{
return transferPort;
}
shared_ptr<NodeConnection> Node::getConnection() {
return nodeConnection;
}
void Node::setHost(string newHostname)
{
Host newHost = Host(newHostname);
return setHost(newHost);
}
void Node::setHost(Host newHost)
{
if (newHost != getHost())
{
host = newHost;
setDirty();
}
}
void Node::setConfig(string newConfig)
{
if (newConfig != getConfig()) {
config = newConfig;
setDirty();
}
}
void Node::setPort(int newPort)
{
if (newPort != getPort()) {
port = newPort;
setDirty();
}
}
void Node::setDiskPath(string newDiskPath) {
if (newDiskPath != getDiskPath()) {
diskPath = newDiskPath;
setDirty();
}
}
void Node::setComPort(int newComPort) {
if (newComPort != getComPort()) {
comPort = newComPort;
setDirty();
}
}
void Node::setTransferPort(int newTransferPort) {
if (newTransferPort != getTransferPort()) {
transferPort = newTransferPort;
setDirty();
}
}
void Node::setConnection(shared_ptr<NodeConnection> newConnection) {
if (newConnection != nodeConnection)
nodeConnection = newConnection;
}
string Node::str(int indentationLevel) const {
string ind = std::string(2 * indentationLevel, ' ');
string ind2 = ind + " ";
/*
With SecondoPLTTYCS
These won't work:
std::string(((4 * indentationLevel) - 2), ' ');
std::string(--indentationLevel, '\t');
With indentationLevel = 2
*/
stringstream ret;
ret << ind << "{" << endl;
ret << ind2 << "Id:" << getId() << endl;
ret << ind2 << "Host:" << getHost().getHostname() << ", ";
ret << "Port:" << getPort() << endl;
ret << ind2 << "Config: " << getConfig() << endl;
ret << ind2 << "DiskPath: " << getDiskPath() << endl;
ret << ind2 << "ComPort: " << getComPort() << endl;
ret << ind2 << "TransferPath: " << getTransferPort() << endl;
ret << ind << "}";
return ret.str();
}
void Node::connectAndConfigure() {
LOG_SCOPE_FUNCTION(INFO);
nodeConnection = make_shared<NodeConnection>(
getHost().getHostname(),
getPort(),
getConfig()
);
//TODO isn't this "connect" redundant to the connect from
// the nodeConnections's constructor?
LOG_F(INFO, "%s", "Connecting to remote node...");
nodeConnection->connect();
LOG_F(INFO, "%s", "Obtaining config params from remote node...");
setComPort(nodeConnection->obtainRemoteConfigParamComPort());
setTransferPort(nodeConnection->obtainRemoteConfigParamTransferPort());
setDiskPath(nodeConnection->obtainRemoteConfigParamDiskPath());
}
bool Node::isConnected() {
return (nodeConnection != nullptr && nodeConnection->isConnected());
}
void Node::startWorker() {
if (isConnected() == false) {
LOG_F(ERROR, "%s",
"Not connected to the worker. Connecing to remote worker...");
connectAndConfigure();
}
nodeConnection->startDBServiceWorker();
}
/**
* Two different node records - despite of their record id - will be
* considered equal as long as they have the same host.
*/
bool Node::operator==(const Node &w2) const
{
// TODO This does not compare disk paths as they had to be extracted from
// the config. Is this ok?
// Implicit DNS resolution of hosts
return (getHost() == w2.getHost() && getPort() == w2.getPort());
}
bool Node::operator!=(const Node &w2) const
{
return !(getHost() == w2.getHost() && getPort() == w2.getPort());
}
std::ostream &operator<<(std::ostream &os, Node const &worker) {
os << "Host: " << worker.getHost().getHostname() << ", Port: ";
os << worker.getPort() << ", Config: " << worker.getConfig();
return os;
}
bool Node::empty() const {
//TODO Should the other members be added, too? Or should the method be
// renamed to
//"valid" to indicate if a node has passed its validation.
return (getHost().getHostname() == "" && getPort() == 0
&& getConfig() == "");
}
//TODO Refactor using the Query class.
string Node::createStatement() const {
// inserttuple["sec-w-0.sec-ws.secondo.svc.cluster.local", 1234,
// '/database/config/SecondoConfig.ini', '/database/secondo-databases',
// 9941, 9942, "dbservice"] consume
stringstream createStatement;
createStatement << "query " << Node::getRelationName() << " inserttuple";
createStatement << "[";
const string quote = "\"";
const string to_text = "totext";
// Hostname, e.g. totext("sec-w-0.sec-ws.secondo.svc.cluster.local")
createStatement << to_text << "(" << quote << getHost().getHostname();
createStatement << quote << ")" << ", ";
// Secondo Port., e.g. 1234
createStatement << std::to_string(getPort()) << ", ";
// Config, e.g. totext("/database/config/SecondoConfig.ini")
createStatement << to_text << "(" << quote << getConfig() << quote << ")"
<< ", ";
// DiskPath, e.g. totext("/database/secondo-databases")
createStatement << to_text << "(" << quote << getDiskPath() << quote << ")"
<< ", ";
// ComPort, e.g. 9941
createStatement << std::to_string(getComPort()) << ", ";
// TransferPort, e.g. 9942
createStatement << std::to_string(getTransferPort()) << ", ";
createStatement << quote << getType() << quote;
createStatement << "] consume";
return createStatement.str();
}
string Node::updateStatement() const {
//TODO Implement later.
return "query 1";
}
//TODO Find an elegant way to use the Query interface to express the creation
// of relations
string Node::createRelationStatement() {
//TODO this neglects the existence of schema migrations - the evolution of
// database schemas over time.
return "let " + getRelationName() + " = [const rel(tuple([Host: text, \
Port: int, Config: text, DiskPath: text, ComPort: int, TransferPort: \
int, Type: string])) value ()]";
}
//TODO Refactor using the Query class.
string Node::findAllStatement(string database) {
stringstream query;
query << "query " << getRelationName() << " feed addid consume";
/* Results should look like this:
* Host : localhost
* Port : 1245
* Config :
* DiskPath : /home/doesnt_exist/secondo
* ComPort : 9941
* TransferPort : 9942
* TID : 4
*/
return query.str();
}
string Node::nodeTypeDBService() {
return "dbservice";
}
string Node::nodeTypeOriginal() {
return "original";
}
}