425 lines
12 KiB
C++
425 lines
12 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2004, University in Hagen, Department of 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
|
|
----
|
|
|
|
//paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}]
|
|
//characters [1] Type: [] []
|
|
//characters [2] Type: [] []
|
|
//[ae] [\"{a}]
|
|
//[oe] [\"{o}]
|
|
//[ue] [\"{u}]
|
|
//[ss] [{\ss}]
|
|
//[Ae] [\"{A}]
|
|
//[Oe] [\"{O}]
|
|
//[Ue] [\"{U}]
|
|
//[x] [$\times $]
|
|
//[->] [$\rightarrow $]
|
|
//[toc] [\tableofcontents]
|
|
|
|
[1] Implementation of class DistributeStreamWorker.
|
|
|
|
[toc]
|
|
|
|
1 DistributeStreamWorker implementation
|
|
|
|
The DistributeStreamWorker gets a client connection and answer with a
|
|
requested stream of tuples. For this a clients needs to send a correct
|
|
request. The DistributeStreamWorker is able to project an filter the
|
|
tuples if requested by the clients. The protocol of the communication is
|
|
described in ~DistributeStreamProtocoll.cpp~. The DistributeStreamWorker
|
|
can send the tuples in binary and in text format.
|
|
The vtuples are stored by the DistributeStreamWorker in a queue.
|
|
|
|
2 Includes
|
|
|
|
*/
|
|
#include "SocketIO.h"
|
|
#include "Algebras/DBService/CommunicationUtils.hpp"
|
|
|
|
#include "DistributeStreamProtocol.h"
|
|
#include "VTHelpers.h"
|
|
#include "Algebras/Relation-C++/RelationAlgebra.h"
|
|
#include "TupleDescr.h"
|
|
#include "VTuple.h"
|
|
|
|
#include "DistributeStreamWorker.h"
|
|
#include "Queue.h"
|
|
|
|
using namespace std;
|
|
|
|
extern NestedList* nl;
|
|
extern QueryProcessor* qp;
|
|
|
|
namespace cstream {
|
|
|
|
/*
|
|
1.1 Constructor
|
|
|
|
Creates a new object of the DistributeStreamWorker with an existing
|
|
connection and a providedFormat.
|
|
|
|
*/
|
|
DistributeStreamWorker::DistributeStreamWorker(Socket* serverConnection,
|
|
const bool providedFormat) :
|
|
_serverConnection(serverConnection),
|
|
_providedFormat(providedFormat),
|
|
_worker(0) {
|
|
LOG << "DistributeStreamWorker::DistributeStreamWorker" << ENDL;
|
|
LOG << "Initializing DistributeStreamWorker" << ENDL;
|
|
}
|
|
|
|
/*
|
|
1.2 Destructor
|
|
|
|
The worker thread will be terminated and the connection will be closed.
|
|
|
|
*/
|
|
DistributeStreamWorker::~DistributeStreamWorker() {
|
|
LOG << "DistributeStreamWorker::~DistributeStreamWorker" << ENDL;
|
|
if(_worker) {
|
|
_worker->interrupt();
|
|
_worker->join();
|
|
}
|
|
if(isConnected())
|
|
_serverConnection->ShutDown();
|
|
}
|
|
|
|
/*
|
|
1.3 Function Definitions
|
|
|
|
The functions provided by the DistributeStreamWorker class are explained
|
|
below.
|
|
|
|
1.3.1 run
|
|
|
|
This function starts the worker thread. The thread is used to handle the
|
|
communication with the client. Only one worker thread can be started for
|
|
a DistributeStreamWorker.
|
|
|
|
*/
|
|
|
|
bool DistributeStreamWorker::run() {
|
|
// start a new thread
|
|
if(!_worker) {
|
|
_worker = new boost::thread(
|
|
boost::bind(&DistributeStreamWorker::communicate, this));
|
|
return true;
|
|
}
|
|
|
|
if(!_worker->joinable()) {
|
|
delete _worker;
|
|
_worker = new boost::thread(
|
|
boost::bind(&DistributeStreamWorker::communicate, this));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
1.3.2 communicate
|
|
|
|
This function is running in a separate thread to handle the communication
|
|
with a connected client. The communication protocol is documented in
|
|
~DistributeStreamProtocol.cpp~. In this function the worker thread get the
|
|
vtuples of the queue, filter and project them as requested by the client
|
|
and sends the filtered and projected tuples to the client in the requested
|
|
format. If the request of the client has an error, the worker closes the
|
|
connection.
|
|
If the queue is empty, the worker thread waits for new vtuple and has to be
|
|
notified.
|
|
|
|
*/
|
|
int DistributeStreamWorker::communicate() {
|
|
LOG << "DistributeStreamServer::communicate" << ENDL;
|
|
iostream& io = _serverConnection->GetSocketStream();
|
|
string request;
|
|
|
|
DBService::CommunicationUtils::receiveLine(io, request);
|
|
LOG << "Query to the server: " << ENDL;
|
|
LOG << request << ENDL;
|
|
|
|
// If the client request the supported types, the client can choose one
|
|
if(request == DistributeStreamProtocol::requestSupportedTypes()) {
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::sendSupportedTypes(_providedFormat));
|
|
|
|
DBService::CommunicationUtils::receiveLine(io, request);
|
|
}
|
|
|
|
string tupledesc;
|
|
ListExpr funList;
|
|
bool format;
|
|
if(DistributeStreamProtocol::requestStream(
|
|
request, tupledesc, funList, format)
|
|
&& format == _providedFormat) {
|
|
|
|
bool filter = !(funList == nl->TheEmptyList());
|
|
|
|
// the TupleDescr to project the stream
|
|
try {
|
|
_selTD = new TupleDescr(tupledesc);
|
|
_tupleType = nl->OneElemList(
|
|
SecondoSystem::GetCatalog()->NumericType(
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
|
_selTD->GetTupleTypeExpr())));
|
|
}
|
|
catch(SecondoException&) {
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::confirmStream(
|
|
"Requested TupleDescr was not OK"));
|
|
LOG << "Requested TupleDescr was not OK" << ENDL;
|
|
_serverConnection->ShutDown();
|
|
|
|
return 0;
|
|
}
|
|
|
|
if(filter) {
|
|
OpTree tree = 0;
|
|
QueryProcessor *qp = new QueryProcessor(nl,
|
|
SecondoSystem::GetAlgebraManager());
|
|
|
|
// Construct the operator tree of the function
|
|
// LOG << "Contruct" << ENDL;
|
|
bool correct = false;
|
|
bool evaluable = false;
|
|
bool defined = false;
|
|
bool isFunction = false;
|
|
ListExpr resultType;
|
|
try {
|
|
qp->Construct( funList,
|
|
correct,
|
|
evaluable,
|
|
defined,
|
|
isFunction,
|
|
tree,
|
|
resultType );
|
|
}
|
|
catch(SI_Error ERR_IN_QUERY_EXPR) {
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::confirmStream(
|
|
"Error in the filter function"));
|
|
_serverConnection->ShutDown();
|
|
delete qp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if(!correct || !defined || !isFunction) {
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::confirmStream(
|
|
"Filterfunction was not OK"));
|
|
_serverConnection->ShutDown();
|
|
qp->Destroy(tree, true);
|
|
delete qp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
ArgVectorPointer funargs = qp->Argument(tree);
|
|
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::confirmStreamOK());
|
|
|
|
_queue.setReady(true);
|
|
|
|
while(true) {
|
|
try {
|
|
boost::unique_lock<boost::mutex> lock(_newTupleGuard);
|
|
_newTupleCV.wait(lock);
|
|
|
|
sendQueue(qp, tree, funargs, io);
|
|
}
|
|
catch (boost::thread_interrupted) {
|
|
sendQueue(qp, tree, funargs, io);
|
|
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::streamDone());
|
|
|
|
qp->Destroy(tree, true);
|
|
delete qp;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::confirmStreamOK());
|
|
|
|
_queue.setReady(true);
|
|
|
|
while(true) {
|
|
try {
|
|
boost::unique_lock<boost::mutex> lock(_newTupleGuard);
|
|
_newTupleCV.wait(lock);
|
|
|
|
sendQueue(io);
|
|
}
|
|
catch (boost::thread_interrupted) {
|
|
sendQueue(io);
|
|
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::streamDone());
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::confirmStream(
|
|
"Request was not OK"));
|
|
LOG << "Request not OK" << ENDL;
|
|
_serverConnection->ShutDown();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
1.3.3 pushTuple
|
|
|
|
Push a tuple to the queue and notifies the waiting thread.
|
|
|
|
*/
|
|
void DistributeStreamWorker::pushTuple(VTuple* tuple) {
|
|
LOG << "DistributeStreamWorker::pushTuple" << ENDL;
|
|
if(_queue.isReady()) {
|
|
_queue.push(tuple);
|
|
_newTupleCV.notify_all();
|
|
}
|
|
}
|
|
|
|
/*
|
|
1.3.4 projectTuple
|
|
|
|
This function projects a given vtuple to a tuple matching to the given
|
|
tupledescr. If the vtuple cannot be projected the result is a nullpointer.
|
|
|
|
*/
|
|
Tuple* DistributeStreamWorker::projectTuple(VTuple* vt) {
|
|
bool projected;
|
|
Tuple* tuple = _selTD->ProjectTuple(vt, projected);
|
|
|
|
return tuple;
|
|
}
|
|
|
|
/*
|
|
1.3.5 filterTuple
|
|
|
|
This function checks wether the filterfunction is true for a given vtuple.
|
|
True is returned when the result of the function is true.
|
|
|
|
*/
|
|
bool DistributeStreamWorker::filterTuple(Tuple* tuple,
|
|
QueryProcessor* qp,
|
|
OpTree& tree,
|
|
ArgVectorPointer& funargs) {
|
|
(*funargs)[0] = tuple;
|
|
Word result;
|
|
qp->EvalS(tree, result, REQUEST);
|
|
if (((Attribute*)result.addr)->IsDefined()) {
|
|
return ((CcBool*)result.addr)->GetBoolval();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
1.3.6 sendTuple
|
|
|
|
This function send a given tuple into the given stream. The function checks
|
|
the requested format. The possible formats are binary and text.
|
|
|
|
*/
|
|
void DistributeStreamWorker::sendTuple(iostream& io, Tuple* tuple) {
|
|
string message;
|
|
if(_providedFormat) {
|
|
message = tuple->WriteToBinStr();
|
|
message = "(" + message + ")";
|
|
}
|
|
else {
|
|
ListExpr tupleValue;
|
|
tupleValue = tuple->Out(_tupleType);
|
|
nl->WriteToString(message, tupleValue);
|
|
}
|
|
|
|
DBService::CommunicationUtils::sendLine(io,
|
|
DistributeStreamProtocol::tupleMessage() + message);
|
|
}
|
|
|
|
/*
|
|
1.3.7 isConnected
|
|
|
|
Tests the connection to the client.
|
|
|
|
*/
|
|
bool DistributeStreamWorker::isConnected() {
|
|
return _serverConnection && _serverConnection->IsOk();
|
|
}
|
|
|
|
/*
|
|
1.3.8 sendQueue
|
|
|
|
Sends the Queue with filtering and projection
|
|
|
|
*/
|
|
void DistributeStreamWorker::sendQueue(QueryProcessor* qp,
|
|
OpTree& tree,
|
|
ArgVectorPointer& funargs,
|
|
iostream& io) {
|
|
while(!_queue.empty()) {
|
|
VTuple* vt = _queue.pop_front();
|
|
|
|
Tuple* tuple;
|
|
if((tuple = projectTuple(vt))) {
|
|
if(filterTuple(tuple, qp, tree, funargs)) {
|
|
sendTuple(io, tuple);
|
|
}
|
|
}
|
|
|
|
vt->DeleteIfAllowed();
|
|
}
|
|
}
|
|
|
|
/*
|
|
1.3.9 sendQueue
|
|
|
|
Sends the Queue with projection but without filtering
|
|
|
|
*/
|
|
void DistributeStreamWorker::sendQueue(iostream& io) {
|
|
while(!_queue.empty()) {
|
|
VTuple* vt = _queue.pop_front();
|
|
|
|
Tuple* tuple;
|
|
if((tuple = projectTuple(vt))) {
|
|
sendTuple(io, tuple);
|
|
}
|
|
|
|
vt->DeleteIfAllowed();
|
|
}
|
|
}
|
|
|
|
};
|