343 lines
8.0 KiB
C++
343 lines
8.0 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2007,
|
|
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
|
|
----
|
|
|
|
|
|
1 QueryExecutor for Distributed-SECONDO
|
|
|
|
|
|
1.1 Includes
|
|
|
|
*/
|
|
|
|
#ifndef __QEXECUTOR_UTILS__
|
|
#define __QEXECUTOR_UTILS__
|
|
|
|
|
|
/*
|
|
|
|
1.2 Typedefs
|
|
|
|
*/
|
|
typedef bool(*myFunc)(string &);
|
|
|
|
/*
|
|
2 Helper class for the query executor
|
|
|
|
*/
|
|
|
|
class QEUtils {
|
|
|
|
public:
|
|
/*
|
|
2.1 Create a new UUID
|
|
|
|
*/
|
|
static void createUUID(string &uuid) {
|
|
char buffer[128];
|
|
|
|
const char *filename = "/proc/sys/kernel/random/uuid";
|
|
FILE *file = fopen(filename, "r");
|
|
|
|
// Does the proc file exists?
|
|
if( access(filename, R_OK ) == -1 ) {
|
|
cerr << "Unable to get UUID from kernel" << endl;
|
|
exit(-1);
|
|
}
|
|
|
|
if (file) {
|
|
while (fscanf(file, "%s", buffer)!=EOF) {
|
|
uuid.append(buffer);
|
|
}
|
|
}
|
|
|
|
fclose(file);
|
|
}
|
|
|
|
|
|
/*
|
|
2.2 Replace placeholder like __NODEID__ in a given string
|
|
|
|
*/
|
|
static void replacePlaceholder(string &query, string placeholder,
|
|
string value) {
|
|
size_t startPos = 0;
|
|
|
|
while((startPos = query.find(placeholder, startPos)) != std::string::npos) {
|
|
query.replace(startPos, placeholder.length(), value);
|
|
startPos += value.length();
|
|
}
|
|
}
|
|
|
|
/*
|
|
2.3 Does the given string contains a placeholder?
|
|
|
|
*/
|
|
static bool containsPlaceholder(string searchString, string placeholder) {
|
|
return searchString.find(placeholder) != std::string::npos;
|
|
}
|
|
|
|
/*
|
|
2.4 Replace shortcuts. The following shortcuts are
|
|
currently supported in DSECONDO:
|
|
|
|
[read roads]
|
|
-> ccollect('roads', ONE)
|
|
[read roads consistency]
|
|
-> ccollect('roads', consistency)
|
|
|
|
[readparallel roads]
|
|
-> ccollect('roads', __TOKENRANGE__, ONE)
|
|
[readparallel roads consistency]
|
|
-> ccollect('roads', __TOKENRANGE__, consistency)
|
|
|
|
[write roads N]
|
|
-> cspread['roads', N, __QUERYUUID__, 'ONE']
|
|
[write roads N consistency]
|
|
-> cspread['roads', N, __QUERYUUID__, consistency]
|
|
|
|
|
|
*/
|
|
static bool replaceShortcuts(string &query) {
|
|
|
|
map<string, myFunc> converterFunctions;
|
|
|
|
converterFunctions["[read"] = &handleReadShortcut;
|
|
converterFunctions["[readparallel"] = &handleReadparallelShortcut;
|
|
converterFunctions["[write"] = &handleWriteShortcut;
|
|
|
|
size_t pos = getPosOfFirstShortcut(query, converterFunctions);
|
|
|
|
while(pos != std::string::npos) {
|
|
|
|
for(map<string, myFunc>::iterator iter = converterFunctions.begin();
|
|
iter != converterFunctions.end(); iter++) {
|
|
|
|
string name = iter -> first;
|
|
|
|
if(query.substr(pos, name.length()) == name) {
|
|
myFunc handler = iter -> second;
|
|
handler(query);
|
|
}
|
|
}
|
|
|
|
pos = getPosOfFirstShortcut(query, converterFunctions);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
2.5 Get position of the first shortcut
|
|
|
|
*/
|
|
static size_t getPosOfFirstShortcut(string &query,
|
|
map<string, myFunc> &converterFunctions) {
|
|
|
|
size_t result = std::string::npos;
|
|
|
|
for(map<string, myFunc>::iterator iter = converterFunctions.begin();
|
|
iter != converterFunctions.end(); iter++) {
|
|
|
|
string name = iter -> first;
|
|
size_t pos = query.find(name);
|
|
|
|
if(result == std::string::npos || result > pos) {
|
|
result = pos;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
2.5 Replace read shortcut
|
|
|
|
*/
|
|
static bool handleReadShortcut(string &query) {
|
|
|
|
size_t pos = query.find("[read ");
|
|
|
|
if(pos == std::string::npos) {
|
|
return false;
|
|
}
|
|
|
|
size_t fields = getShortcutFieldCount(query, pos);
|
|
|
|
string relation = getShortcutField(query, pos, 1);
|
|
string replacement;
|
|
|
|
if(fields == 1) {
|
|
replacement = "ccollect('" + relation + "')";
|
|
} else {
|
|
string consistency = getShortcutField(query, pos, 2);
|
|
replacement = "ccollect('" + relation + "', '"
|
|
+ consistency + "')";
|
|
}
|
|
|
|
string shortcut = getFirstShortcut(query, pos);
|
|
|
|
replacePlaceholder(query, shortcut, replacement);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
2.6 Replace readparallel shortcut
|
|
|
|
*/
|
|
static bool handleReadparallelShortcut(string &query) {
|
|
|
|
size_t pos = query.find("[readparallel ");
|
|
|
|
if(pos == std::string::npos) {
|
|
return false;
|
|
}
|
|
|
|
size_t fields = getShortcutFieldCount(query, pos);
|
|
|
|
string relation = getShortcutField(query, pos, 1);
|
|
string replacement;
|
|
|
|
if(fields == 1) {
|
|
replacement = "ccollectrange('" + relation + "', "
|
|
+ "__TOKENRANGE__)";
|
|
} else {
|
|
string consistency = getShortcutField(query, pos, 2);
|
|
replacement = "ccollectrange('" + relation + "', "
|
|
+ "__TOKENRANGE__, '" + consistency + "')";
|
|
}
|
|
|
|
string shortcut = getFirstShortcut(query, pos);
|
|
|
|
replacePlaceholder(query, shortcut, replacement);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
2.7 Replace write shortcut
|
|
|
|
*/
|
|
static bool handleWriteShortcut(string &query) {
|
|
|
|
size_t pos = query.find("[write ");
|
|
|
|
if(pos == std::string::npos) {
|
|
return false;
|
|
}
|
|
|
|
size_t fields = getShortcutFieldCount(query, pos);
|
|
|
|
string relation = getShortcutField(query, pos, 1);
|
|
string partitionKey = getShortcutField(query, pos, 2);
|
|
string replacement;
|
|
|
|
if(fields == 2) {
|
|
replacement = "cspread['" + relation + "', "
|
|
+ partitionKey
|
|
+ ", '__QUERYUUID__']";
|
|
} else {
|
|
string consistency = getShortcutField(query, pos, 3);
|
|
replacement = "cspread['" + relation + "', "
|
|
+ partitionKey
|
|
+ ", '__QUERYUUID__','"
|
|
+ consistency + "']";
|
|
}
|
|
|
|
string shortcut = getFirstShortcut(query, pos);
|
|
replacePlaceholder(query, shortcut, replacement);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
2.8 get number of fields, pointed by pos
|
|
|
|
*/
|
|
static size_t getShortcutFieldCount(string &query, size_t pos) {
|
|
|
|
size_t fields = 0;
|
|
|
|
for(size_t i = pos; i < query.length(); i++) {
|
|
if(query[i] == ' ') {
|
|
fields++;
|
|
}
|
|
|
|
if(query[i] == ']') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fields;
|
|
}
|
|
|
|
/*
|
|
2.9 Get the content of a field
|
|
|
|
*/
|
|
static string getShortcutField(string &query, size_t pos, size_t field) {
|
|
size_t currentField = 0;
|
|
stringstream ss;
|
|
|
|
for( ; pos < query.length(); pos++) {
|
|
|
|
if(query[pos] == ' ') {
|
|
currentField++;
|
|
continue;
|
|
}
|
|
|
|
if(query[pos] == '[') {
|
|
continue;
|
|
}
|
|
|
|
if(query[pos] == ']') {
|
|
break;
|
|
}
|
|
|
|
if(currentField > field) {
|
|
break;
|
|
}
|
|
|
|
if(currentField == field) {
|
|
ss << query[pos];
|
|
}
|
|
|
|
}
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
static string getFirstShortcut(string &query, size_t pos) {
|
|
|
|
size_t end = query.find(']', pos);
|
|
size_t length = end-pos+1;
|
|
|
|
string shortcut = query.substr(pos, length);
|
|
|
|
return shortcut;
|
|
}
|
|
|
|
};
|
|
|
|
#endif |