/* ---- This file is part of SECONDO. Copyright (C) 2014, University in Hagen, 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 ---- Jan Kristof Nidzwetzki //paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}] //paragraph [10] Footnote: [{\footnote{] [}}] //[TOC] [\tableofcontents] [TOC] 0 Overview 1 Includes and defines */ #include #include #include #include #include #include #include #include #include #include #include #include "CassandraHelper.h" #include "CassandraAdapter.h" #include "CassandraResult.h" #include "CassandraTuplePrefetcher.h" // Activate debug messages //#define __DEBUG__ #define MAX_PENDING_FUTURES 30 #define MAX_PENDING_FUTURES_LOW_WATERMARK 20 using namespace std; //namespace to avoid name conflicts namespace cassandra { // Init static variables const string CassandraAdapter::METADATA_TUPLETYPE = "_TUPLETYPE"; CassError CassandraAdapter::connect_session(CassSession* session, const CassCluster* cluster) { CassError rc = CASS_OK; CassFuture* future = cass_session_connect(session, cluster); cass_future_wait(future); rc = cass_future_error_code(future); if (rc != CASS_OK) { errorFlag = true; CassandraHelper::print_error(future); } cass_future_free(future); // suppress warn messages cass_log_set_level(CASS_LOG_ERROR); return rc; } void CassandraAdapter::connect(bool singleNodeLoadBalancing) { CassError rc = CASS_OK; stringstream ss; cluster = cass_cluster_new(); session = cass_session_new(); cass_cluster_set_contact_points(cluster, contactpoint.c_str()); // Set high bytes watermark to 2MB, so each connection can // have 1 MB of data pending // // Watermarks are deprecated since version 2.8 of the driver // see https://datastax-oss.atlassian.net/browse/CPP-538 #if (CASS_VERSION_MAJOR < 2 || \ (CASS_VERSION_MAJOR == 2 && CASS_VERSION_MINOR < 8)) cass_cluster_set_write_bytes_high_water_mark(cluster, 2 * 1024 * 1024); #endif // Switch to single node policy if(singleNodeLoadBalancing) { cass_cluster_set_whitelist_filtering(cluster, contactpoint.c_str()); } rc = connect_session(session, cluster); if (rc != CASS_OK) { disconnect(); } else { ss << "USE "; ss << keyspace; // Switch keyspace executeCQLSync(ss.str(), CASS_CONSISTENCY_ALL); cout << "Cassandra: Connection successfully established" << endl; cout << "You are connected to host " << contactpoint << " keyspace " << keyspace << endl; cout << "SingleNodeLoadBalancing: " << singleNodeLoadBalancing << endl; } } bool CassandraAdapter::isConnected() { if(session) { return true; } else { return false; } } bool CassandraAdapter::writeDataToCassandra(string relation, string partition, string node, string key, string value, string consistenceLevel, bool sync) { bool result = false; // Convert consistence level CassConsistency consistency = CassandraHelper::convertConsistencyStringToEnum(consistenceLevel); // Write Data and wait for result if(sync) { result = executeCQLSync( getInsertCQL(relation, partition, node, key, value), consistency ); } else { result = executeCQLASync( getInsertCQL(relation, partition, node, key, value), consistency ); } return result; } bool CassandraAdapter::writeDataToCassandraPrepared( const CassPrepared* preparedStatement, string partition, string node, string key, char *value, size_t value_length, string consistenceLevel, bool sync) { if(! isConnected() ) { cerr << "Cassandra session not ready" << endl; return false; } if(preparedStatement == NULL) { cerr << "Prepared statement is null" << endl; return false; } CassStatement* statement = cass_prepared_bind(preparedStatement); cass_statement_set_consistency(statement, CassandraHelper::convertConsistencyStringToEnum(consistenceLevel)); // Bind parameter cass_statement_bind_string(statement, 0, partition.c_str()); cass_statement_bind_string(statement, 1, node.c_str()); cass_statement_bind_string(statement, 2, key.c_str()); cass_statement_bind_bytes(statement, 3, reinterpret_cast(value), value_length); // Build future and execute CassFuture* future = cass_session_execute(session, statement); // Execution sync or async? if(sync) { executeCQLFutureSync(future); } else { pendingFutures.push_back(future); waitForPendingFuturesIfNeeded(); } cass_statement_free(statement); return true; } void CassandraAdapter::freePreparedStatement( const CassPrepared* preparedStatement) { if(preparedStatement != NULL) { cass_prepared_free(preparedStatement); preparedStatement = NULL; } } const CassPrepared* CassandraAdapter::prepareCQLInsert(string relation) { CassError rc = CASS_OK; const CassPrepared* result = NULL; if(! isConnected() ) { cerr << "Cassandra session not ready" << endl; return NULL; } string cqlQuery = getInsertCQL(relation, "?", "?", "?", "?"); CassFuture* future = cass_session_prepare(session, cqlQuery.c_str()); cass_future_wait(future); rc = cass_future_error_code(future); if(rc != CASS_OK) { errorFlag = true; CassandraHelper::print_error(future); } else { result = cass_future_get_prepared(future); } cass_future_free(future); return result; } string CassandraAdapter::getInsertCQL(string relation, string partition, string node, string key, string value) { stringstream ss; ss << "INSERT INTO "; ss << relation; ss << " (partition, node, key, value)"; ss << " VALUES ("; string quote = "'"; // Prepared statemnt? No quoting! if((key.compare("?") == 0) && (value.compare("?") == 0) && (node.compare("?") == 0) && (partition.compare("?") == 0)) { quote = ""; } ss << quote << partition << quote << ", "; ss << quote << node << quote << ", "; ss << quote << key << quote << ", "; ss << value << ");"; // Blob value, no quoting necessary return ss.str(); } CassandraResult* CassandraAdapter::getAllTables(string keyspace) { stringstream ss; ss << "SELECT columnfamily_name FROM "; ss << "system.schema_columnfamilies WHERE keyspace_name='"; ss << keyspace; ss << "';"; return readDataFromCassandra(ss.str(), CASS_CONSISTENCY_ONE); } bool CassandraAdapter::insertPendingTokenRange(size_t queryId, string ip, TokenRange *tokenrange) { stringstream ss; ss << "INSERT INTO system_pending(queryid, ip, begintoken, endtoken)"; ss << " values(" << queryId << ", '" << ip << "', " << "'"; ss << tokenrange->getStart() << "', '" << tokenrange->getEnd() << "');"; bool result = executeCQLSync(ss.str(), CASS_CONSISTENCY_QUORUM); return result; } void CassandraAdapter::deletePendingTokenRange(size_t queryId, string ip, TokenRange *tokenrange) { stringstream ss; ss << "DELETE FROM system_pending where queryid=" << queryId; ss << " and ip='" << ip << "' and begintoken='"; ss << tokenrange->getStart() << "';"; executeCQLSync(ss.str(), CASS_CONSISTENCY_QUORUM); } bool CassandraAdapter::getNodeForPendingTokenRange(string &cassandraNode, size_t queryId, TokenRange *tokenrange) { stringstream ss; ss << "SELECT ip FROM system_pending where queryid=" << queryId; ss << " and begintoken='" << tokenrange->getStart() << "';"; bool pending = false; CassandraResult* result = readDataFromCassandra( ss.str(), CASS_CONSISTENCY_ONE); while(result->hasNext()) { pending = true; result->getStringValue(cassandraNode, 0); } if(result != NULL) { delete result; result = NULL; } return pending; } bool CassandraAdapter::getTupleTypeFromTable(string relation, string &result) { stringstream ss; ss << "SELECT value FROM "; ss << relation; ss << " WHERE partition = '"; ss << CassandraAdapter::METADATA_TUPLETYPE; ss << "';"; string query = ss.str(); #ifdef __DEBUG__ cout << "Query: " << query << endl; #endif // Execute query CassandraResult* cassandraResult = readDataFromCassandra(query, CASS_CONSISTENCY_ONE, false); if(cassandraResult == NULL) { return false; } if(! cassandraResult->hasNext() ) { delete cassandraResult; cassandraResult = NULL; return false; } cassandraResult -> getStringValue(result, 0); // Cleanup result object delete cassandraResult; cassandraResult = NULL; return true; } CassandraTuplePrefetcher* CassandraAdapter::readTable(string relation, string consistenceLevel) { stringstream ss; ss << "SELECT key, value from "; ss << relation; ss << ";"; string query = ss.str(); CassConsistency casConsistenceLevel = CassandraHelper::convertConsistencyStringToEnum(consistenceLevel); return new CassandraTuplePrefetcher(session, query, casConsistenceLevel); } CassandraTuplePrefetcher* CassandraAdapter::readTableRange(string relation, string consistenceLevel, string begin, string end) { stringstream ss; ss << "SELECT key, value from "; ss << relation; ss << " where token(partition) >= " << begin << " "; ss << "and token(partition) <= " << end; ss << ";"; string query = ss.str(); CassConsistency casConsistenceLevel = CassandraHelper::convertConsistencyStringToEnum(consistenceLevel); return new CassandraTuplePrefetcher(session, query, casConsistenceLevel); } CassandraTuplePrefetcher* CassandraAdapter::readTableCreatedByQuery( string relation, string consistenceLevel, int queryId) { vector ranges; if (! getProcessedTokenRangesForQuery(ranges, queryId) ) { cerr << "Unable to fetch token ranges for query: " << queryId << endl; return NULL; } map nodeNames; if(! getNodeData(nodeNames) ) { cerr << "Unable to fetch node data for query: " << queryId << endl; return NULL; } vector queries; // Generate token range queries; for(vector::iterator iter = ranges.begin(); iter != ranges.end(); ++iter) { TokenRange range = *iter; stringstream ss; ss << "SELECT key, value from "; ss << relation << " where node = '" << range.getQueryUUID() << "';"; queries.push_back(ss.str()); } CassConsistency casConsistenceLevel = CassandraHelper::convertConsistencyStringToEnum(consistenceLevel); return new CassandraTuplePrefetcher(session, queries, casConsistenceLevel); } CassandraTuplePrefetcher* CassandraAdapter::readTableLocal(string relation, string consistenceLevel) { // Lokal tokens vector localTokenRange; vector localTokens; vector peerTokens; getLocalTokenRanges(localTokenRange, localTokens, peerTokens); vector queries; // Generate token range queries; for(vector::iterator iter = localTokenRange.begin(); iter != localTokenRange.end(); ++iter) { stringstream ss; ss << "SELECT key, value from "; ss << relation << " "; ss << "where "; TokenRange interval = *iter; // Include token begin if(interval.getStart() == LLONG_MIN) { ss << "token(partition) >= " << interval.getStart() << " "; } else { ss << "token(partition) > " << interval.getStart() << " "; } ss << "and token(partition) <= " << interval.getEnd(); ss << ";"; queries.push_back(ss.str()); } CassConsistency casConsistenceLevel = CassandraHelper::convertConsistencyStringToEnum(consistenceLevel); return new CassandraTuplePrefetcher(session, queries, casConsistenceLevel); } CassandraResult* CassandraAdapter::readDataFromCassandra(string cql, CassConsistency consistenceLevel, bool printError) { if(! isConnected() ) { cerr << "Cassandra session not ready" << endl; return NULL; } return new CassandraResult(session, cql, consistenceLevel, printError); } bool CassandraAdapter::getLocalTokenRanges( vector &localTokenRange, vector &localTokens, vector &peerTokens) { vector allTokenRanges; bool result = getAllTokenRanges(allTokenRanges, localTokens, peerTokens); // Do filtering of local intervals for(vector::iterator iter = allTokenRanges.begin(); iter != allTokenRanges.end(); ++iter) { TokenRange interval = *iter; if(interval.isLocalTokenRange()) { localTokenRange.push_back(interval); } } // Print debug Info #ifdef __DEBUG__ cout << "Peer ranges are: "; copy(peerTokens.begin(), peerTokens.end(), std::ostream_iterator(cout, " ")); cout << std::endl; cout << "Local ranges are: "; copy(localTokenRange.begin(), localTokenRange.end(), std::ostream_iterator(cout, " ")); cout << std::endl; #endif return result; } bool CassandraAdapter::getAllTokenRanges( vector &allTokenRange) { vector localTokens; vector peerTokens; return getAllTokenRanges(allTokenRange, localTokens, peerTokens); } bool CassandraAdapter::getAllTokenRanges( vector &allTokenRange, vector &localTokens, vector &peerTokens) { // Calculate local token ranges if(! getLocalTokens(localTokens)) { return false; } if(! getPeerTokens(peerTokens)) { return false; } sort(localTokens.begin(), localTokens.end()); sort(peerTokens.begin(), peerTokens.end()); // Merge and sort tokens vector allTokens; allTokens.reserve(localTokens.size() + peerTokens.size()); allTokens.insert(allTokens.end(), localTokens.begin(), localTokens.end()); allTokens.insert(allTokens.end(), peerTokens.begin(), peerTokens.end() ); sort(allTokens.begin(), allTokens.end()); // Last position in the vector int lastTokenPos = allTokens.size() - 1; // Is last token-range splitted? // // If so, the two token-ranges are // (begin, LLONG_MAX] and [LLONG_MIN, end] if((allTokens.at(lastTokenPos)).getToken() != LLONG_MAX) { // Add end interval TokenRange interval( (allTokens.at(lastTokenPos)).getToken(), LLONG_MAX, (allTokens.at(lastTokenPos)).getIp()); allTokenRange.push_back(interval); // Add start interval TokenRange interval2( LLONG_MIN, (allTokens.at(0)).getToken(), (allTokens.at(0)).getIp()); allTokenRange.push_back(interval2); } else { // Add only the end interval TokenRange interval( (allTokens.at(lastTokenPos - 1)).getToken(), LLONG_MAX, (allTokens.at(lastTokenPos - 1)).getIp()); } // Find all local token ranges between nodes and add them for(size_t i = 0; i < allTokens.size() - 1; ++i) { long long currentToken = (allTokens.at(i)).getToken(); long long nextToken = (allTokens.at(i + 1)).getToken(); TokenRange tokenrange(currentToken, nextToken, (allTokens.at(i)).getIp()); allTokenRange.push_back(tokenrange); } sort(allTokenRange.begin(), allTokenRange.end()); return true; } bool CassandraAdapter::createTable(string tablename, string tupleType) { stringstream ss; ss << "CREATE TABLE IF NOT EXISTS "; ss << tablename; ss << " ( partition text, node text, key text,"; ss << " value blob, PRIMARY KEY(partition, node, key));"; bool resultCreate = executeCQLSync(ss.str(), CASS_CONSISTENCY_ALL); // Write tupletype if(resultCreate) { // Use a prepared statement to handle the blob correctly const CassPrepared *statement; statement = prepareCQLInsert(tablename); char *tupleString = new char[tupleType.length() + 1]; strcpy(tupleString, tupleType.c_str()); bool resultInsert = writeDataToCassandraPrepared(statement, CassandraAdapter::METADATA_TUPLETYPE, CassandraAdapter::METADATA_TUPLETYPE, CassandraAdapter::METADATA_TUPLETYPE, tupleString, tupleType.length(), "ALL", true); if(statement != NULL) { freePreparedStatement(statement); statement = NULL; } if(tupleString != NULL) { delete[] tupleString; tupleString = NULL; } if(resultInsert) { // New table is created and the // tuple type is stored successfully stringstream ss_index; ss_index << "CREATE INDEX ON "; ss_index << tablename; ss_index << " (node);"; executeCQLSync(ss_index.str(), CASS_CONSISTENCY_ALL); cout << "<<<< INDEX " << ss_index.str() << endl; return true; } } return false; } bool CassandraAdapter::dropTable(string tablename) { stringstream ss; /*ss << "DROP TABLE IF EXISTS "; ss << tablename; ss << ";"; */ // Only truncate table to avoid recreation issues ss << "TRUNCATE " << tablename << ";"; return executeCQLSync(ss.str(), CASS_CONSISTENCY_ALL); } void CassandraAdapter::waitForPendingFuturesIfNeeded() { if(pendingFutures.size() > MAX_PENDING_FUTURES) { int waitForFutures = (pendingFutures.size() - MAX_PENDING_FUTURES_LOW_WATERMARK); for(int i = 0; i < waitForFutures; i++) { CassFuture* future = pendingFutures[i]; cass_future_wait(future); } // Force removal of finished futures removeFinishedFutures(true); } } void CassandraAdapter::waitForPendingFutures() { if(pendingFutures.empty()) { return; } for(vector::iterator iter = pendingFutures.begin(); iter != pendingFutures.end(); ++iter) { CassFuture* future = *iter; cass_future_wait(future); } // Force removal of finished futures removeFinishedFutures(true); } void CassandraAdapter::disconnect() { if( ! isConnected()) { return; } cout << "Disconnecting from cassandra" << endl; waitForPendingFutures(); // Close session and cluster CassFuture* close_future = cass_session_close(session); cass_future_wait(close_future); cass_future_free(close_future); cass_cluster_free(cluster); cass_session_free(session); cluster = NULL; session = NULL; } bool CassandraAdapter::executeCQLSync (string cql, CassConsistency consistency) { if(! isConnected() ) { cerr << "Cassandra session not ready" << endl; return false; } CassFuture* future = executeCQL(cql, consistency); return executeCQLFutureSync(future); } bool CassandraAdapter::executeCQLASync (string cql, CassConsistency consistency) { if(! isConnected() ) { cerr << "Cassandra session not ready" << endl; return false; } CassFuture* future = executeCQL(cql, consistency); pendingFutures.push_back(future); waitForPendingFuturesIfNeeded(); return true; } void CassandraAdapter::removeFinishedFutures(bool force) { // The cleanup is not needed everytime if(pendingFutures.size() % 10 != 0 && force == false) { return; } // Are some futures finished? for(vector::iterator iter = pendingFutures.begin(); iter != pendingFutures.end(); ) { CassFuture* future = *iter; // Remove finished futures if(cass_future_ready(future) == cass_true) { if(cass_future_error_code(future) != CASS_OK) { errorFlag = true; CassandraHelper::print_error(future); } cass_future_free(future); iter = pendingFutures.erase(iter); } else { ++iter; } } } bool CassandraAdapter::executeCQLFutureSync(CassFuture* future) { bool result = true; if(! isConnected() ) { cerr << "Cassandra session not ready" << endl; return false; } // Wait for execution cass_future_wait(future); if(cass_future_error_code(future) != CASS_OK) { errorFlag = true; CassandraHelper::print_error(future); result = false; } if(future != NULL) { cass_future_free(future); future = NULL; } return result; } CassFuture* CassandraAdapter::executeCQL (string cql, CassConsistency consistency) { if(! isConnected() ) { cerr << "Cassandra session not ready" << endl; return NULL; } CassStatement* statement = cass_statement_new(cql.c_str(), 0); cass_statement_set_consistency(statement, consistency); CassFuture* future = cass_session_execute(session, statement); cass_statement_free(statement); return future; } bool CassandraAdapter::getTokensFromQuery (string query, vector &result, string peer) { CassError rc = CASS_OK; CassFuture* future = executeCQL(query, CASS_CONSISTENCY_QUORUM); cass_future_wait(future); rc = cass_future_error_code(future); if (rc != CASS_OK) { errorFlag = true; CassandraHelper::print_error(future); return false; } const CassResult* cas_result = cass_future_get_result(future); CassIterator* iterator = cass_iterator_from_result(cas_result); while(cass_iterator_next(iterator)) { const CassRow* row = cass_iterator_get_row(iterator); // No peer argument was given, fetch from database string currentPeer = peer; if(currentPeer.empty()) { // Convert data into ip addresss CassInet peerData; cass_value_get_inet(cass_row_get_column_by_name(row, "peer"), &peerData); char buf[INET_ADDRSTRLEN]; uv_inet_ntop(AF_INET, peerData.address, buf, sizeof(buf)); currentPeer = buf; } const CassValue* value = cass_row_get_column(row, 0); CassIterator* items_iterator = cass_iterator_from_collection(value); while(cass_iterator_next(items_iterator)) { const char* item_string; size_t item_length; cass_value_get_string(cass_iterator_get_value(items_iterator), &item_string, &item_length); char value_buffer[128]; memcpy(value_buffer, item_string, item_length); value_buffer[item_length] = '\0'; long long tokenLong = atol(value_buffer); result.push_back(CassandraToken(tokenLong, currentPeer)); } cass_iterator_free(items_iterator); } if(cas_result != NULL) { cass_result_free(cas_result); cas_result = NULL; } if(iterator != NULL) { cass_iterator_free(iterator); iterator = NULL; } if(future != NULL) { cass_future_free(future); future = NULL; } return true; } bool CassandraAdapter::getLocalTokens(vector &result) { return getTokensFromQuery( "SELECT tokens FROM system.local", result, string("127.0.0.1")); } bool CassandraAdapter::getPeerTokens(vector &result) { return getTokensFromQuery( "SELECT tokens,peer FROM system.peers", result, string("")); } bool CassandraAdapter::truncateMetatables() { vector queries; vector ranges; int highestQueryId = 0; size_t clearTry = 0; string getSystemProgress = string( "SELECT ip, begintoken, endtoken, queryuuid FROM system_progress"); queries.push_back(string("TRUNCATE system_queries;")); queries.push_back(string("TRUNCATE system_state;")); queries.push_back(string("TRUNCATE system_progress;")); queries.push_back(string("TRUNCATE system_pending;")); queries.push_back(string("TRUNCATE system_tokenranges;")); do { if(clearTry > 20) { cerr << "Error: system_progress is not empty after 100 seconds" << endl; return false; } for(vector::iterator iter = queries.begin(); iter != queries.end(); ++iter) { string query = *iter; // Create queries table bool result = executeCQLSync( query, CASS_CONSISTENCY_ALL ); if(! result) { cout << "Unable to execute query: " << query << endl; return false; } } clearTry++; ranges.clear(); sleep(5); getTokenrangesFromQuery(ranges, getSystemProgress); CassandraResult* result = getGlobalQueryState(); highestQueryId = 0; // Determine the highest executed query if(result != NULL) { while(result -> hasNext()) { int lastExecutedQuery = result -> getIntValue(1); if(lastExecutedQuery > highestQueryId) { highestQueryId = lastExecutedQuery; } } delete result; } } while(! ranges.empty() || highestQueryId > 0 || clearTry < 2) ; return true; } void CassandraAdapter::getQueriesToExecute(vector &result) { CassandraResult* queries = readDataFromCassandra ("SELECT id, query, version from system_queries", CASS_CONSISTENCY_ALL); while(queries != NULL && queries->hasNext()) { // Error while fetching data from cassandra if(queries == NULL) { return; } long long res; string myResult; size_t id = queries->getIntValue(0); queries -> getStringValue(myResult, 1); res = queries->getBigIntValue(2); result.push_back(CassandraQuery(id, myResult, (time_t) res)); } if(queries != NULL) { delete queries; queries = NULL; } sort(result.begin(), result.end(), QueryComperator()); } CassandraResult* CassandraAdapter::getGlobalQueryState( CassConsistency consistency, bool printError) { string cql("SELECT ip, lastquery FROM system_state"); return readDataFromCassandra(cql, consistency, printError); } void CassandraAdapter::quoteCqlStatement(string &query) { size_t startPos = 0; string placeholder = "'"; string value = "''"; while((startPos = query.find(placeholder, startPos)) != std::string::npos) { query.replace(startPos, placeholder.length(), value); startPos += value.length(); } } bool CassandraAdapter::copyTokenRangesToSystemtable(string localip) { vector allIntervals; getAllTokenRanges(allIntervals); for(vector::iterator iter = allIntervals.begin(); iter != allIntervals.end(); ++iter) { TokenRange interval = *iter; // Build CQL query stringstream ss; ss << "INSERT INTO system_tokenranges(ip, begintoken, endtoken) "; ss << "values("; if(interval.isLocalTokenRange()) { ss << "'" << localip << "',"; } else { ss << "'" << interval.getIp() << "',"; } ss << "'" << interval.getStart() << "',", ss << "'" << interval.getEnd() << "'", ss << ");"; // Update last executed command bool result = executeCQLSync( ss.str(), CASS_CONSISTENCY_ALL ); if(! result) { return false; } } return true; } bool CassandraAdapter::getTokenRangesFromSystemtable ( vector &result) { string query = string("SELECT ip, begintoken, endtoken FROM system_tokenranges"); return getTokenrangesFromQuery(result, query); } bool CassandraAdapter::getProcessedTokenRangesForQuery ( vector &result, int queryId, CassConsistency consistency, bool printError) { stringstream ss; ss << "SELECT ip, begintoken, endtoken, queryuuid FROM system_progress "; ss << " WHERE queryid = " << queryId; return getTokenrangesFromQuery(result, ss.str(), consistency); } bool CassandraAdapter::getTokenrangesFromQuery ( vector &result, string query, CassConsistency consistency, bool printError) { CassError rc = CASS_OK; CassFuture* future = executeCQL(query, consistency); cass_future_wait(future); rc = cass_future_error_code(future); if (rc != CASS_OK) { if(printError) { errorFlag = true; CassandraHelper::print_error(future); } return false; } // Does the query return queryuuids? bool containsQueryuuid = query.find("queryuuid") != string::npos; const CassResult* cas_result = cass_future_get_result(future); CassIterator* iterator = cass_iterator_from_result(cas_result); while(cass_iterator_next(iterator)) { const CassRow* row = cass_iterator_get_row(iterator); const char* result_string; size_t item_length; string ip; string beginToken; string endToken; string queryuuid = ""; cass_value_get_string(cass_row_get_column(row, 0), &result_string, &item_length); ip.append(result_string, item_length); cass_value_get_string(cass_row_get_column(row, 1), &result_string, &item_length); beginToken.append(result_string, item_length); cass_value_get_string(cass_row_get_column(row, 2), &result_string, &item_length); endToken.append(result_string, item_length); long long beginLong = atol(beginToken.c_str()); long long endLong = atol(endToken.c_str()); if(containsQueryuuid) { cass_value_get_string(cass_row_get_column(row, 3), &result_string, &item_length); queryuuid.append(result_string, item_length); } result.push_back(TokenRange(beginLong, endLong, ip, queryuuid)); } if(cas_result != NULL) { cass_result_free(cas_result); cas_result = NULL; } if(iterator != NULL) { cass_iterator_free(iterator); iterator = NULL; } if(future != NULL) { cass_future_free(future); future = NULL; } // Sort result sort(result.begin(), result.end()); return true; } bool CassandraAdapter::getHeartbeatData(map &result) { CassandraResult *cas_result = readDataFromCassandra( string("SELECT ip, heartbeat FROM system_state"), CASS_CONSISTENCY_QUORUM); while(cas_result->hasNext()) { string ip; long long res; res = cas_result->getBigIntValue(1); cas_result->getStringValue(ip, 0); result.insert(std::pair(ip,(time_t) res)); } delete cas_result; return true; } bool CassandraAdapter::getNodeData(map &result) { CassandraResult *cas_result = readDataFromCassandra( string("SELECT ip, node FROM system_state"), CASS_CONSISTENCY_QUORUM); while(cas_result->hasNext()) { string ip; string node; cas_result->getStringValue(ip, 0); cas_result->getStringValue(node, 1); result.insert(std::pair(ip, node)); } delete cas_result; return true; } }