Due to a very exciting, recently launched project at work, I’ve had to interface with Cassandra through C++ code. As anyone who has done this can testify, the API docs are vague at best, and there are very few examples out there. The constant API changes between 0.x versions and the fact that the Cassandra API has its docs and Thrift has its own, but there is nothing bridging the two isn’t helpful either.
So at the moment it is very much a case of dissecting header files and looking at implementation in the Thrift generated source files.
The only somewhat useful example of using Cassandra with C++ one can find online is this, but due to the API changes, this is now outdated (it’s still worth a read).
So in the hope that nobody else will have to spend the better part of a day piecing things together to achieve even the most basic thing, here’s an example which works with Cassandra 0.7 and Thrift 0.6.
First of all, create a new keyspace and a column family, using cassandra-cli:
1234567891011
[default@unknown] create keyspace nm_example;
c647b2c0-83e2-11e0-9eb2-e700f669bcfc
Waiting for schema agreement...
... schemas agree across the cluster
[default@unknown] use nm_example;
Authenticated to keyspace: nm_example
[default@nm_example] create column family nm_cfamily with comparator=BytesType and default_validation_class=BytesType;
30466721-83e3-11e0-9eb2-e700f669bcfc
Waiting for schema agreement...
... schemas agree across the cluster
[default@nm_example]
Now go to the directory where you have cassandra installed and enter the interface/ directory and run: thrift -gen cpp cassandra.thrift
This will create the gen-cpp/ directory. From this directory, you need to copy all files bar the Cassandra_server.skeleton.cpp one to wherever you intend to keep your sources.
Here’s some example code which inserts, retrieves, updates, retrieves and deletes keys:
#include "Cassandra.h"#include <protocol/TBinaryProtocol.h>#include <thrift/transport/TSocket.h>#include <thrift/transport/TTransportUtils.h>usingnamespacestd;usingnamespaceapache::thrift;usingnamespaceapache::thrift::protocol;usingnamespaceapache::thrift::transport;usingnamespaceorg::apache::cassandra;usingnamespaceboost;staticstringhost("127.0.0.1");staticintport=9160;int64_tgetTS(){/* If you're doing things quickly, you may want to make use of tv_usec * or something here instead */time_tltime;ltime=time(NULL);return(int64_t)ltime;}intmain(){shared_ptr<TTransport>socket(newTSocket(host,port));shared_ptr<TTransport>transport(newTFramedTransport(socket));shared_ptr<TProtocol>protocol(newTBinaryProtocol(transport));CassandraClientclient(protocol);conststring&key="your_key";ColumnPathcpath;ColumnParentcp;ColumnOrSuperColumncsc;Columnc;c.name.assign("column_name");c.value.assign("Data for our key to go into column_name");c.timestamp=getTS();c.ttl=300;cp.column_family.assign("nm_cfamily");cp.super_column.assign("");cpath.column_family.assign("nm_cfamily");/* This is required - thrift 'feature' */cpath.__isset.column=true;cpath.column="column_name";try{transport->open();cout<<"Set keyspace to 'dpdns'.."<<endl;client.set_keyspace("nm_example");cout<<"Insert key '"<<key<<"' in column '"<<c.name<<"' in column family '"<<cp.column_family<<"' with timestamp "<<c.timestamp<<"..."<<endl;client.insert(key,cp,c,org::apache::cassandra::ConsistencyLevel::ONE);cout<<"Retrieve key '"<<key<<"' from column '"<<cpath.column<<"' in column family '"<<cpath.column_family<<"' again..."<<endl;client.get(csc,key,cpath,org::apache::cassandra::ConsistencyLevel::ONE);cout<<"Value read is '"<<csc.column.value<<"'..."<<endl;c.timestamp++;c.value.assign("Updated data going into column_name");cout<<"Update key '"<<key<<"' in column with timestamp "<<c.timestamp<<"..."<<endl;client.insert(key,cp,c,org::apache::cassandra::ConsistencyLevel::ONE);cout<<"Retrieve updated key '"<<key<<"' from column '"<<cpath.column<<"' in column family '"<<cpath.column_family<<"' again..."<<endl;client.get(csc,key,cpath,org::apache::cassandra::ConsistencyLevel::ONE);cout<<"Updated value is: '"<<csc.column.value<<"'"<<endl;cout<<"Remove the key '"<<key<<"' we just retrieved. Value '"<<csc.column.value<<"' timestamp "<<csc.column.timestamp<<" ..."<<endl;client.remove(key,cpath,csc.column.timestamp,org::apache::cassandra::ConsistencyLevel::ONE);transport->close();}catch(NotFoundException&nf){cerr<<"NotFoundException ERROR: "<<nf.what()<<endl;}catch(InvalidRequestException&re){cerr<<"InvalidRequest ERROR: "<<re.why<<endl;}catch(TException&tx){cerr<<"TException ERROR: "<<tx.what()<<endl;}return0;}
Say we’ve called the file cassandra_example.cpp, and you have the files mentioned above in the same directory, you can comile things like this:
Another thing worth mentioning is Padraig O'Sullivan’slibcassandra, which may or may not be worth a look depending on what you want to do and what versions of Thrift and Cassandra you’re tied to.