さくらVPSでcassandra-0.8.0-beta1を試す



まだ、cassandra-0.7.4もきちんと理解していないのに、「devアットcassandra.apache.org」にて「[VOTE] Apache Cassandra 0.8.0-beta1」が
流れていたので、CQLを試したく、インストールしてみた。0.8.0-beta1 artifactsというところにお試しがあったのでインストールしてみました。

他のバージョンに関しては、こちらをご参考にしてください。

 

apache-cassandra-0.8.0-beta1-bin.tar.gzをインストール

0.6系、0.7系と同様に既存のサービスを止め、「/var/log/cassandra/」「/var/lib/cassandra/」に配置してある
ログデータやDBデータを削除しました。一点、「./conf/cassandra.yaml」の記述ではまり、cassandraサービスが
立ち上がりませんでした。
 

apache-cassandra-0.8.0-beta1のサービス起動時にエラー

サービス起動時に以下のエラーがでてしまい、「java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map」
と言われている。システムの環境変数に0.7.4の情報を設定していたのでその情報が悪さしているものと思い一通り綺麗に
してみたが、現象は変わりませんでした。

ERROR [main] 2011-04-19 xx:xx:xx,xxx DatabaseDescriptor.java (line 420) Fatal configuration error error
Can't construct a java object for tag:yaml.org,2002:org.apache.cassandra.config.Config; exception=Cannot create property=seed_provider for JavaBean=org.apache.cassandra.config.Config@709446e4; java.lang.reflect.InvocationTargetException
 in "<reader>", line 10, column 1:
    cluster_name: 'Test Cluster'
    ^
        at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:372)
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:177)
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:136)
        at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:122)
        at org.yaml.snakeyaml.Loader.load(Loader.java:52)
        at org.yaml.snakeyaml.Yaml.load(Yaml.java:166)
        at org.apache.cassandra.config.DatabaseDescriptor.<clinit>(DatabaseDescriptor.java:139)
        at org.apache.cassandra.service.AbstractCassandraDaemon.setup(AbstractCassandraDaemon.java:98)
        at org.apache.cassandra.service.AbstractCassandraDaemon.activate(AbstractCassandraDaemon.java:314)
        at org.apache.cassandra.thrift.CassandraDaemon.main(CassandraDaemon.java:80)
Caused by: org.yaml.snakeyaml.error.YAMLException: Cannot create property=seed_provider for JavaBean=org.apache.cassandra.config.Config@709446e4; java.lang.reflect.InvocationTargetException
        at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:305)
        at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.construct(Constructor.java:184)
        at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:370)
        ... 9 more
Caused by: org.yaml.snakeyaml.error.YAMLException: java.lang.reflect.InvocationTargetException
        at org.yaml.snakeyaml.constructor.Constructor$ConstructSequence.construct(Constructor.java:589)
        at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:177)
        at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:298)
        ... 11 more
Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at org.yaml.snakeyaml.constructor.Constructor$ConstructSequence.construct(Constructor.java:587)
        ... 13 more
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map
        at org.apache.cassandra.config.SeedProviderDef.<init>(SeedProviderDef.java:34)
        ... 18 more

 

apache-cassandra-0.8.0-beta1のソースにデバッグ情報を入れ、確認をしてみる

apache-cassandra-0.8.0-beta1-src.tar.gzをダウンロードし、「org.apache.cassandra.config.SeedProviderDef」クラスの
34行目を確認してみました。

public class SeedProviderDef
{
    public String class_name;
    public Map<String, String> parameters;
    
    public SeedProviderDef(LinkedHashMap p)
    {
        class_name = (String)p.get("class_name");
        parameters = (Map<String, String>)((List)p.get("parameters")).get(0);
    }
}

シンプルなソースで間違えるはずは無いのですが、「java.lang.String cannot be cast to java.util.Map」と言われてます。
SeedProviderDefクラスがどこで利用されているかというと、org.apache.cassandra.config.Configで利用されているようです。


0.7.4の時が、どんなソースだったかというと

   public String[] seeds;
    public DiskAccessMode disk_access_mode = DiskAccessMode.auto;

という感じでした。
ちなみに、0.8betaでは、下記の様な感じです。

    public SeedProviderDef seed_provider;
    public DiskAccessMode disk_access_mode = DiskAccessMode.auto;

 

SeedProviderDefを設定しているところを探す

「org.apache.cassandra.config.DatabaseDescriptor」クラスで初期化しているところを発見しました。

            TypeDescription seedDesc = new TypeDescription(SeedProviderDef.class);
            seedDesc.putMapPropertyType("parameters", String.class, String.class);
            constructor.addTypeDescription(seedDesc);

 
TypeDescriptionは、サードパーティライブラリのようです。「org.yaml.snakeyaml.TypeDescription」
読み込みも間違ってなさそうなので、ログを出力し、なにが格納されているかみてみることにしました。
 

cassandra-0.8.0-beta1のソースをビルドする

SeedProviderDefクラスの「p.get("parameters")」には、なにが入っているのかログを出力してみることにしました。
こんな感じです。

public class SeedProviderDef
{
    private static Logger logger = LoggerFactory.getLogger(SeedProviderDef.class);
    public String class_name;
    public Map<String, String> parameters;

    public SeedProviderDef(LinkedHashMap p)
    {
        logger.info("Start SeedProviderDef");
        class_name = (String)p.get("class_name");
        logger.info("aaa**:" + p);
        parameters = (Map<String, String>)((List)p.get("parameters")).get(0);
    }
}

Antがインストールされていれば、「Ant jar」でビルドすることができました。
build/apache-cassandra-0.8.0-beta1-SNAPSHOT.jarというファイルができたので、実行時のJarとして
入れ替えてみました。

すると。。

 INFO xx:xx:xx,xxx aaa**:127.0.0.1
ERROR xx:xx:xx,xxx Fatal configuration error error
Can't construct a java object for tag:yaml.org,2002:org.apache.cassandra.config.Config; exception=Cannot create property=seed_provider for JavaBean=org.apache.cassandra.config.Config@250d593e; java.lang.reflect.InvocationTargetException
 in "<reader>", line 10, column 1:
    cluster_name: 'Test Cluster'
    ^

「aaa**:127.0.0.1」とでました。なんかKeyがなさそうです。
conf/cassandra.yamlを確認してみます。

0.7.4の時

seeds:
    #- 127.0.0.1

 
0.8betaの時

seed_provider:
    # Addresses of hosts that are deemed contact points.
    # Cassandra nodes use this list of hosts to find each other and learn
    # the topology of the ring.  You must change this if you are running
    # multiple nodes!
    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
          # seeds is actually a comma-delimited list of addresses.
          #- seeds: "127.0.0.1"

書き方が変わっており、初め「- 127.0.0.1」しか書いておりませんでした。(コピーアンドペースト
「- seeds: "127.0.0.1"」と書かなければいけなかったようです。*1

「- seeds: "127.0.0.1"」と書き直し、起動したところうまく動作させてことができました。
 

最後に

README.txtにしたがって、「family Users」に値を設定しようとしたらエラーがでました。

READMEより抜粋

  [default@unknown] create keyspace Keyspace1;
  ece86bde-dc55-11df-8240-e700f669bcfc
  [default@unknown] use Keyspace1;
  Authenticated to keyspace: Keyspace1
  [default@Keyspace1] create column family Users with comparator=UTF8Type and default_validation_class=UTF8Type and key_validation_class=UTF8Type;
  737c7a71-dc56-11df-8240-e700f669bcfc

  [default@KS1] set Users[jsmith][first] = 'John';
  Value inserted.
  [default@KS1] set Users[jsmith][last] = 'Smith';
  Value inserted.
  [default@KS1] set Users[jsmith][age] = long(42);
  Value inserted.
  [default@KS1] get Users[jsmith];
  => (column=last, value=Smith, timestamp=1287604215498000)
  => (column=first, value=John, timestamp=1287604214111000)
  => (column=age, value=42, timestamp=1287604216661000)
  Returned 3 results.

 
エラー内容

[default@Keyspace1] set Users[jsmith][first] = 'John';
org.apache.cassandra.db.marshal.MarshalException: cannot parse 'jsmith' as hex bytes

 
[jira]メーリングリストを眺めていると、「[Created] (CASSANDRA-2497) Issues with Update Column Family and adding a key_validation_class」
とあり、「I figured out that problem is in the CLI, will attach a patch tomorrow morning! 」とありました。

CLI: issue with keys being interpreted as hex and causing SET statement to fail

ただ、よくみるとパッチがあったので、パッチをあてて再度実行してみました。
(パッチの中身は、こちらを利用)

 cd src/java/org/apache/cassandra/cli/
 vi CASSANDRA-2497.patch
 patch < CASSANDRA-2497.patch

 
パッチ適用後、再度、「ant jar」で新しくjarを作りなおします。
cassandraのサービスを再起動後、cassandra-cliを試してみました。

 $ cassandra-cli
    Welcome to the Cassandra CLI.

    Type 'help;' or '?' for help.
    Type 'quit;' or 'exit;' to quit.

  [default@unknown] connect xx.xxx.xxx.xxx/9160;
  Connected to: "Test Cluster" on xx.xxx.xxx.xxx/9160
  [default@unknown]
  [default@unknown] use Keyspace1;
  Authenticated to keyspace: Keyspace1
  [default@Keyspace1] set Users[jsmith][first] = 'John';
  Value inserted.
  [default@Keyspace1] get Users[jsmith][first];
  => (column=first, value=John, timestamp=1303202057480000)
  [default@Keyspace1] exit;

無事、Column Familyに値を追加することができました。
 


*1:ダブルクォートで書き込まなくとも大丈夫なようです。