Eden Ridgway's Blog

.Net and Web Development Information

  Home :: Contact :: Syndication  :: Login
  105 Posts :: 1 Stories :: 78 Comments :: 3 Trackbacks

Search

Article Categories

Archives

Post Categories

Development

General

I've been quite curious about the various BigTable like implementations as they could have some bearing on what I am involved with at work. After reading various write ups about the competing approaches (e.g. HyperTable, HBase, Dynomite, Voldemort, Mongodb) I decided that Cassandra looked like the best option for what I'm after. What I didn't realise was that it wasn't going to be as straight forward as it appears to set it all up as there is no end-to-end guide of getting started with it. So the objective of this post is not to explain Cassandra but save you several hours of jumping all over the web trying to work out what you should do next and how to generate the necessary C# Cassandra Thrift client code. If parts of the post don't apply, e.g. VM setup, simply skip ahead to the parts that do. If you want more information about Cassandra you should check out the following posts:

 

So to get Cassandra up and running in a Virtual Machine (or physical if you choose) you should follow the following steps (valid as at 5 Nov 2010):

  1. Create a virtual machine to host Ubuntu 9.10 x86 Desktop. I use VirtualBox as my VM host on windows so I will refer to this here but feel free to substitute it with you favourite VM software. The VM I created has 384MB allocated to it with an 8GB virtual hard drive using a bridged network adapter (so it can be accessed from the Windows XP host). Once you've gone through the install process install the client tools so that you change the screen resolution, share folders, etc. To do this with virtual box go to Devices > Install Guest Additions and then open up a terminal window and execute

    sudo /media/cdrom/VBoxLinuxAdditions-x86.run

    Once this is complete you will need to reboot your VM.
  2. Now it is time to install Cassandra/Thrift prerequisites and software that we will to set everything up:

    sudo apt-get install libboost-dev automake libtool flex bison pkg-config g++ -y
    sudo apt-get install sun-java6-jdk -y
    sudo apt-get apt-get install ant -y

  3. Once that is done we can install other useful Ubuntu software that we will use:

    sudo apt-get install rapidsvn -y
    sudo apt-get install monodevelop -y

    I also like to install the following:

    sudo apt-get install nautilus-open-terminal -y
    sudo apt-get install samba smbfs smbclient winbind -y
    sudo apt-get install nautilus-share -y

  4. You may discover that there is an issue with your Java runtime home directory. If that occurs, select Sun's Java Runtime as the default Java version by running the following command from the terminal window and selecting the third option:

    sudo update-alternatives --config java

  5. Now open up Nautilus by going to Places > Home Folder. Right click and create a Development folder. Within the Development folder create another two folders: Cassandra and Thrift.
  6. We can now get the source for Cassandra and Thrift. Run RapidSVN by going to Applications > Programming > RapidSVN. Check out the source from SVN by going to the RapidSVN menu option Repository > Checkout. In the URL enter http://svn.apache.org/repos/asf/incubator/thrift/trunk and for the Destination Directory browse to the Thrift development folder. So it should look like this:

    image
    Now get the Cassandra code by doing the same thing but entering http://svn.apache.org/repos/asf/incubator/cassandra/trunk as the URL and selecting the Cassandra directory.
  7. Once we have all the code we are ready to compile Cassandra, so let's do that by executing the following commands from the terminal window:

    cd ~/Development/Cassandra
    ant

  8. Start the Cassandra server by opening a new terminal window and running the following commands:

    sudo ~/Development/Cassandra/bin/cassandra -f

    The running server will look like the screenshot below. You should take note of the thrift binding address of localhost/127.0.0.1:9160.

    image
  9. Now we want to get communicating with the server, so we will need to compile Thrift so that we can use it to generate our C# client:

    cd ~/Development/Thrift
    ./bootstrap.sh
    ./configure
    make
    sudo make install

  10. Now we can finally generate a C# client for the Thrift calls to Cassandra:

    cd ~/Development/Cassandra/interface/
    ~/Development/Thrift/compiler/cpp/thrift -gen csharp cassandra.thrift

    This will create the following directories inside of the Cassandra/interface folder: gen-csharp/Apache/Cassandra. These files along with the Thrift.dll will be copied into a new demo project we will create using MonoDevelop in the Development folder. So again in the terminal window execute:

    mkdir ~/Development/CassandraDemo
    cp ~/Development/Cassandra/interface/gen-csharp ~/Development/CassandraDemo -R
    cp ~/Development/Thrift/lib/csharp/Thrift.dll ~/Development/CassandraDemo

  11. Open up MonoDevelop and create a new console application by going to File > New > Solution. Now do the following:
    1. Select Console project
    2. Enter CassandraDemo as the name
    3. For the location browse to the Development folder that we created in your home directory.
    4. Uncheck the 'Create separate Solution directory' check box.
    5. Click the Forward button
    6. Don't make any changes on the next screen and just click Ok.
    7. Right click on the CassandraDemo project in the left tree view and select Add > Add Files.... Navigate to ~/Development/CassandraDemo/gen-csharp/Apache/Cassandra and select all the files in the folder. You will now have a project that looks like this:

      image
    8. Add a reference to the Thrift assembly by right clicking on References and selecting Edit References. Change to the .Net Assembly tab and double click on the Thrift.dll and click OK.
    9. Now we can add the sample code to test it all out. So double click on Main.cs to ensure that is the class in focus in the editor. Replace the contents of the file with this:
      namespace CassandraDemo
      {
         
      using System;
          using
      System.Collections.Generic;
          using
      System.Diagnostics;

          using
      Apache.Cassandra;
          using
      Thrift.Protocol;
          using
      Thrift.Transport;

          class
      Program
          {
             
      static void Main(string[] args)
              {
                  TTransport transport
      = new TSocket("localhost", 9160);
                 
      TProtocol protocol = new TBinaryProtocol(transport);
                 
      Cassandra.Client client = new Cassandra.Client(protocol);
                  
                 
      Console.WriteLine("Opening connection");
                 
      transport.Open();

                 
      System.Text.Encoding utf8Encoding = System.Text.Encoding.UTF8;

                  long
      timeStamp = DateTime.Now.Millisecond;
                 
      ColumnPath nameColumnPath = new ColumnPath() 
                                              { 
                                                  Column_family
      = "Standard1"
                                                  Column
      = utf8Encoding.GetBytes("name")
                                              }
      ;

                 
      Console.WriteLine("Inserting name columns");

                 
      //Insert the data into the column 'name'
                 
      client.insert("Keyspace1",
                               
      "1",
                                nameColumnPath,
                                utf8Encoding.GetBytes(
      "Joe Bloggs"),
                                timeStamp,
                                ConsistencyLevel.ONE)
      ;

                 
      client.insert("Keyspace1",
                               
      "2",
                                nameColumnPath,
                                utf8Encoding.GetBytes(
      "Joe Soap"),
                                timeStamp,
                                ConsistencyLevel.ONE)
      ;

                 
      //Simple single value get using the key to get column 'name'
                 
      ColumnOrSuperColumn returnedColumn = client.get("Keyspace1", "1", nameColumnPath, ConsistencyLevel.ONE);
                 
      Console.WriteLine("Column Data in Keyspace1/Standard1: name: {0}, value: {1}",
                                    utf8Encoding.GetString(returnedColumn.Column.Name),
                                    utf8Encoding.GetString(returnedColumn.Column.Value))
      ;

                 
      Console.WriteLine("Getting splice range");

                 
      //Read an entire row
                 
      SlicePredicate predicate = new SlicePredicate()
                                             {
                                                Slice_range
      = new SliceRange()
                                                              {
                                                                 
      //Start and Finish cannot be null
                                                                 
      Start = new byte[0], 
                                                                  Finish
      = new byte[0],
                                                                  Count 
      = 10,
                                                                  Reversed
      = false
                                                             
      }
                                             }
      ;

                 
      ColumnParent parent = new ColumnParent() { Column_family = "Standard1" };
                 
      Dictionary<string , List<ColumnOrSuperColumn>> results = client.multiget_slice("Keyspace1"
                                                                           
      new List<string>() { "1", "2"}, 
                                                                            parent, 
                                                                            predicate, 
                                                                            ConsistencyLevel.ONE)
      ;

                  foreach
      (KeyValuePair<string, List<ColumnOrSuperColumn>> resultPair in results)
                  {
                      Console.WriteLine(
      "Key: {0}", resultPair.Key);

                      foreach
      (ColumnOrSuperColumn resultColumn in resultPair.Value)
                      {
                          Column column
      = resultColumn.Column;
                         
      Console.WriteLine("name: {0}, value: {1}", utf8Encoding.GetString(column.Name), utf8Encoding.GetString(column.Value));
                     
      }
                  }

                  Console.WriteLine(
      "Closing connection");
                 
      transport.Close();
             
      }
          }
      }
    10. Hit F5 and watch the Application Output window. This is what you should see:

      image

  12. Hopefully this is enough to get you going and have you fill in the remaining gaps. If you found it useful please post a comment. If the Cassandra guys would like to use the C# example they are welcome to it. Good luck!
posted on Friday, November 06, 2009 12:32 AM

Feedback

# re: .Net Developer's Guide to Getting Started with Cassandra 12/2/2009 1:50 AM Jonathan Ellis
Hey Eden,

Just saw this post; nicely done. We'll take you up on the offer of the sample code -- and do note that the wiki is publicly editable, but you have to click Login to get to the register page. (Yay for usability. :)

# re: .Net Developer's Guide to Getting Started with Cassandra 1/1/2010 1:35 PM Kha Nguyen
Hi,

Thank for your demo. I use .Net for Cassandra and have 1 problem on TimeUUIDType.

I use Microsoft SDK (UUIDGen.exe) to gen UUID version 1
And I use Guid to convert to byte array. But Cassandra thow an excaption : TimeUUID only makes sense with version 1 UUIDs

Pls tell me an idea. Thank

Comments have been closed on this topic.