kallaspriit / Cassandra-PHP-Client-Library

Cassandra PHP-based client library for managing and querying your Cassandra cluster
http://cassandra-php-client-library.com
103 stars 25 forks source link

Solution: Counter support #14

Closed madhandennis closed 12 years ago

madhandennis commented 12 years ago

For those of you looking for counter support in this excellent library, here it is. Add it to CassandraColumnFamily class in the Cassandra.php file and you are good to go.

public function add($key, $column, $value = 1, $superColumn = null, $consistency = null) {
            $columnParent = $this->createColumnParent($superColumn);
            $timestamp = CassandraUtil::getTimestamp();

            $counter = new cassandra_CounterColumn();
            $counter->name = CassandraUtil::pack(
                    $column,
                    $this->getColumnNameType()
            );
            $counter->value = $value;

            $result = $this->cassandra->call(
            'add',
            $key,
            $columnParent,
            $counter,
            $consistency
        );
        }

invoke as

$cassandra->cf('columnfamily')->add('key', 'column') to increment by 1
$cassandra->cf('columnfamily')->add('key', 'column', -1) to decrement by 1
$cassandra->cf('columnfamily')->add('key', 'column', 5) to increment by 5
$cassandra->cf('columnfamily')->add('key', 'column', -5) to decrement by 5

for super column based counter CFs

$cassandra->cf('columnfamily')->add('key', 'column',1 , 'supercol1') to increment by 1
$cassandra->cf('columnfamily')->add('key', 'column', -1, 'supercol1') to decrement by 1
$cassandra->cf('columnfamily')->add('key', 'column', 5, 'supercol1') to increment by 5
$cassandra->cf('columnfamily')->add('key', 'column', -5, 'supercol1') to decrement by 5

Thanks for kallaspriit for such an awesome library!

Cheers

kallaspriit commented 12 years ago

Thanks alot for your contribution, I will verify this soon and add it to the library :)

madhandennis commented 12 years ago

Glad to be of help :) thank you for a great library. I found the API n design very nice.

Sent from my iPhone

On 10 May, 2012, at 8:24 PM, Priit Kallas reply@reply.github.com wrote:

Thanks alot for your contribution, I will verify this soon and add it to the library :)


Reply to this email directly or view it on GitHub: https://github.com/kallaspriit/Cassandra-PHP-Client-Library/issues/14#issuecomment-5623705

madhandennis commented 12 years ago

Hi Priit,

Please find the modified parseSliceRow(...) method below to support the get requests for counter cfs.

protected function parseSliceRow(cassandra_ColumnOrSuperColumn $row) {
        $result = array();
        if ($row->column !== null) {
            $nameType = $this->getColumnNameType();
            $valueType = $this->getColumnValueType($row->column->name);

            $name = CassandraUtil::unpack($row->column->name, $nameType);
            $value = CassandraUtil::unpack($row->column->value, $valueType);

            $result[$name] = $value;
        } else if($row->super_column !== null) {
            $superNameType = null;

            $superName = CassandraUtil::unpack(
                $row->super_column->name,
                $superNameType
            );

            $values = array();

            foreach ($row->super_column->columns as $column) {
                $nameType = $this->getColumnNameType();
                $valueType = $this->getColumnValueType($column->name);

                $name = CassandraUtil::unpack($column->name, $nameType);
                $value = CassandraUtil::unpack($column->value, $valueType);

                $values[$name] = $value;
            }

            $result[$superName] = $values;
        } else if ($row->counter_column !== null) {
            $nameType = $this->getColumnNameType();
            $valueType = $this->getColumnValueType($row->counter_column->name);

            $name = CassandraUtil::unpack($row->counter_column->name, $nameType);
            $value = CassandraUtil::unpack($row->counter_column->value, $valueType);

            $result[$name] = $value;
        } else if ($row->counter_super_column !== null) {
            $superNameType = null;

            $superName = CassandraUtil::unpack(
                $row->counter_super_column->name,
                $superNameType
            );

            $values = array();

            foreach ($row->counter_super_column->columns as $column) {
                $nameType = $this->getColumnNameType();
                $valueType = $this->getColumnValueType($column->name);

                $name = CassandraUtil::unpack($column->name, $nameType);
                $value = CassandraUtil::unpack($column->value, $valueType);

                $values[$name] = $value;
            }

            $result[$superName] = $values;
        } else {
            // @codeCoverageIgnoreStart
            throw new Exception('Expected either normal or super column');
            // @codeCoverageIgnoreEnd
        }

        return $result;
    }

Not sure if I will need to modify any other method since at the moment I am only using set n get. Will update if I add any other modifications w.r.t counters in here.

kallaspriit commented 12 years ago

Did you use a special column type or column family default validator such as "CounterColumnType" with it? Having some troubles getting it to work and don't have much time to debug it.

madhandennis commented 12 years ago

Yea unless you set the default validation class to CounterColumnType. Otherwise cassandra doesnt recognize it as counters and will treat it as a regular CF/SCF. (http://wiki.apache.org/cassandra/Counters)

madhandennis commented 12 years ago

Example from their wiki:

create column family counterCF with default_validation_class=CounterColumnType and replicate_on_write=true;

kallaspriit commented 12 years ago

Tried this but at least my Windows work computer Cassandra just choked on it, crashing the server.

I guess I should try it on the Ubuntu box but don't have time for that just now.

Could you provide an example that would work in example.php creating the column family, adding, modifying some record and fetching it back?

madhandennis commented 12 years ago

Will do.... I havent tried creating a Counter CF thru the library yet since I do it using Cassandra Cluster Admin, but yea will try it out n paste it in here....

Does it crash when creating the counter cf or when you try to access it? Also IIRC you will have to update the thrift packages to one supporting counter CF. And for the info, I am on cassandra 1.0.9

madhandennis commented 12 years ago

Here is the working creation via the library. Same code will apply for SCF counters as well except you will need to add the super column at the end for add and get (Example is above in the original post)

        $this->cassandra->createStandardColumnFamily(
            'mykeyspace', // keyspace name
            'mycountercf',             // the column-family name
            array(), //Dont specify any columns since it will be fixed by cassandra
            'org.apache.cassandra.db.marshal.AsciiType',
            'org.apache.cassandra.db.marshal.CounterColumnType'
        );

        $this->cassandra->cf('mycountercf')->add('myrowkey', 'some_counter'); //creates a row with key myrowkey and a column called some_counter and sets it to 1
        $this->cassandra->cf('mycountercf')->add('myrowkey', 'some_counter', 5); //adds 5 to some_counter and makes it 6
        $this->cassandra->cf('mycountercf')->add('myrowkey', 'some_counter', -2); //decrements the counter by 2
        $cntr = $this->cassandra->cf('mycountercf')->get('myrowkey'); //fetch back the counter
        var_dump($cntr);
madhandennis commented 12 years ago

Oh, and I havent made any changes to support counters in your active record adapter though since I use your core library directly.

kallaspriit commented 12 years ago

Thanks a lot, added the core counters functionality and will probably add some syntatic sugar on top of it to Cassandra and active-record soon :)