2013年1月11日金曜日
lift-mapperのモデルのコードジェネレータ作ってみた
2012年10月23日火曜日
sbt 0.12.Xでscala.tools.nsc.MissingRequirementErrorが出て、compile出来ない件
sbtのバージョンを0.11.3から、0.12.1に上げてみたところ、プロジェクトをコンパイルしようとすると@sbt console > compile [info] Compiling 1 Scala source to PROJECT_PATH\target\scala-2.9.2\classes... [trace] Stack trace suppressed: run 'last compile:compile' for the full output. [error] (compile:compile) scala.tools.nsc.MissingRequirementError: object scala not found. [error] Total time: 0 s, completed 2012/10/23 12:38:06な感じのエラーが出るようになりました。いろいろ調べた結果、
libraryDependencies := ...サンプルコード(というほどでもないが;; みたいな感じに、依存ライブラリを上書きしてしまっていることが原因でした。 解決方法は、
- :=は使わず、+=や<+=などを使う
- :=で上書きした後に、
libraryDependencies <++= (autoScalaLibrary, sbtPlugin, scalaVersion) apply Classpaths.autoLibraryDependency
で、必要なライブラリを追加する。
2012年8月6日月曜日
MySQLでupdateしてinsertするとDeadLockが発生する
原因は、1つのTransaction内でupdateをかけてみて更新件数が0の場合、insertをするという操作をしているところでした。updateを行った際にそのKeyが存在しないと行ロックを広く取ってしまうことが原因みたいです。(あくまでらしいです。ソースコードなどまではおっていません。)
始めはO/R Mapper周りのバグかなと思ってたので、MySQL側の挙動であることを確定させるために検証コードも書いてみました。
ちなみに、Thread数が1ではこの問題は発生しません。
Sample code
App.scalaimport java.sql.DriverManager import scala.util.Random object App{ def main(args : Array[String]) { Class.forName("com.mysql.jdbc.Driver") val con = DriverManager.getConnection("jdbc:mysql://localhost/test", username, password); val st = con.createStatement() st.executeUpdate("""drop table DeadLockCheck""") st.executeUpdate("""create table if not exists DeadLockCheck( id INT PRIMARY KEY, c INT DEFAULT 0);""") st.close() con.close() val threads = (0 until 5).map(i =>{ val t = new MyThread() t.start() t }) threads.foreach(_.join) } } object MyThread{ var random = new Random } class MyThread extends Thread{ override def run() = { for(i <- 0 until 50){ val con = DriverManager.getConnection("jdbc:mysql://localhost/test", username, password); con.setAutoCommit(false); val st = con.createStatement() val id = MyThread.random.nextInt.abs if(st.executeUpdate("""update DeadLockCheck set c = c + 1 where id = %s""".format(id)) <= 0){ st.executeUpdate("""insert DeadLockCheck values(%s,1)""".format(id)) } con.commit() st.close() con.close() } } }build.sbt
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.21"
結果
[info] Running App [error] (Thread-82) com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction [error] (Thread-85) com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction [error] (Thread-84) com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) at com.mysql.jdbc.Util.getInstance(Util.java:386) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1065) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4074) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4006) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2468) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2629) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2713) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1794) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1712) at MyThread$$anonfun$run$1.apply$mcVI$sp(App.scala:43) at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:75) at MyThread.run(App.scala:36) com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) at com.mysql.jdbc.Util.getInstance(Util.java:386) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1065) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4074) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4006) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2468) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2629) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2713) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1794) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1712) at MyThread$$anonfun$run$1.apply$mcVI$sp(App.scala:43) at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:75) at MyThread.run(App.scala:36) com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) at com.mysql.jdbc.Util.getInstance(Util.java:386) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1065) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4074) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4006) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2468) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2629) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2713) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1794) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1712) at MyThread$$anonfun$run$1.apply$mcVI$sp(App.scala:43) at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:75) at MyThread.run(App.scala:36) [success] Total time: 1 s, completed 2012/08/06 19:01:10
参考
InnoDBのネクストキーロックによるデッドロックの例2012年7月29日日曜日
Windows上でredmine2.0.3 + MySQLを動かす
1. Rubyの環境構築
Rubyインストーラーダウンロードページから、- Ruby 1.9.3-p194
- DevKit-tdm-32-4.5.2-20111229-1559-sfx.exe
Rubyは、installerを実行すればOK。
※この時、Ruby のインストール先を変更する場合は、ディレクトリにスペースが含まれていないところにする。
DevKitは、実行すると解凍先を聞いてくるので、適当な場所に解凍して解答したディレクトリでコマンドプロンプトから
ruby dk.rb init ruby dk.rb installを実行してインストールする。
2. MySQLの準備
MySQLを準備し、- redmine
- redmine_develop
3. Redmineのインストール
Reamine から、2.0.3をダウンロードしてきて、サーバーを実行したい所に解凍する。 redmineを解凍したディレクトリでgem install bundler bundle install --without development test rmagickを実行する。 (RMagickはWindows環境だとインストールが大変なので、除外しておきます。)
4. conf/database.yml設定
conf/database.yml.exampleをコピーして名前をdatabase.ymlに変更する。database.ymlのadapterをmysqlからmysql2に変更し、DBのusernameとpasswordも変更する。
rake generate_secret_token rake db:migrate rake redmine:load_default_data
5. サーバーの起動
script/rails server webrickを実行すればOK。
production modeで起動したい場合は、
RAILS_ENV=production rake generate_secret_token RAILS_ENV=production rake db:migrate RAILS_ENV=production rake redmine:load_default_dataでDBを準備して、
ruby script/rails server webrick -e productionでサーバーを起動。
とらぶるしゅーてぃんぐ
`require': Incorrect MySQL client library version! This gem was compiled for 6.0.0 but the client library is 5.0.20a. (RuntimeError)のエラーが出る場合 まず
gem install mysql2を実行し、結果に表示されるzipファイルをダウンロードする。
※私が実行したときは6.0.2だったので以下のURLからダウンロードしました。 http://dev.mysql.com/get/Downloads/Connector-C/mysql-connector-c-noinstall-6.0.2-win32.zip/from/pick ダウンロードしファイルを解凍して、中のlib\libmysql.dllをRubyの$RUBY_HOME$\bin以下にコピーしてあげればOKです。
参考にしたページ
2012年5月30日水曜日
ScalaからAWS SDK for Javaを使ってDynamoDBをいじったTips
使ってみた時に詰まった点をメモってみました。
1. ResourceNotFoundExceptionが出る原因
以下のような例外が発生する場合の原因と対処法です。
[error] (run-main) Status Code: 400, AWS Service: AmazonDynamoDB, AWS Request ID: QSQDQO1RMAIDU4S2G6QNCR7S3JVV4KQNSO5AEMVJF66Q9ASUAAJG, AWS Error Code: ResourceNotFoundException, AWS Error Message: Requested resource not found Status Code: 400, AWS Service: AmazonDynamoDB, AWS Request ID: QSQDQO1RMAIDU4S2G6QNCR7S3JVV4KQNSO5AEMVJF66Q9ASUAAJG, AWS Error Code: ResourceNotFoundException,AWS Error Message: Requested resource not found
原因1 Endpointが設定されていない
val client : AmazonDynamoDBClient = ...// init client.setEndpont("http://dynamodb.ap-northeast-1.amazonaws.com"); // <- 東京RegionのEndpoint設定。自分のDynamoDBを使用しているRegionを設定しましょう。Endpoingの一覧はこちら
原因2 Tableが作成されていない
指定したTableが存在しない場合にも同じ例外が発生します。Tableが正常に作成されているかと、プログラム中でTable名の指定が間違ってないかを確認しましょう。
Tableがまだ作成されていない場合は、ManagedConsoleから作成してあげましょう。
2. ValidationExceptionが出る原因
以下のような例外が発生する場合の原因と対処法です。
[error] (run-main) Status Code: 400, AWS Service: AmazonDynamoDB, AWS Request ID: HE5SG08RJAMBQQUBJ031DRGRTVVV4KQNSO5AEMVJF66Q9ASUAAJG, AWS Error Code: ValidationException, AWS Error Message: The provided key element does not match the schema Status Code: 400, AWS Service: AmazonDynamoDB, AWS Request ID: HE5SG08RJAMBQQUBJ031DRGRTVVV4KQNSO5AEMVJF66Q9ASUAAJG, AWS Error Code: ValidationException, AWS Error Message: The provided key element does not match the schema
原因1 HashKeyまたはRangeKeyの型が違う
HashKeyとRangeKeyの型が間違っている場合に良く起こります。 Table定義を確認して、StringとNumber型の指定が正しいことを確認してください。
new AttributeValue().withS("hogehoge") //Table定義ではNumberになっている場合コレが原因になる
3. O/R mapperを使ってRangeKeyにDate型を指定したけど、queryで上手くフィルターできない
O/R mapperでDateを使用する場合は、DynamoDB上ではISO8601の日付フォーマットの文字列として保存されます。
import com.amazonaws.util.DateUtils DateUtils dateUtils = new DateUtils(); dateUtils.formatIso8601Date(date) dateUtils.parseIso8601Date(dateString)で、変換できます。queryやscan時のConditionで指定する場合は、このメソッドを使いましょう。
4. ScalaからAWS SDKのO/R mapperを使う
Java Beansにしか対応していないので、通常のScalaPlainObjectでは上手く認識してくれません。
基本的には、@BeansInfoアノテーションをつければ、getter/setterを生成してくれるので変数の定義に関しては問題ありません。
しかし、varにつけたアノテーションは、コンパイルされるタイミングで、同名のprivate fieldのほうに付けれられてしまいます。
そのため、AWS SDKのアノテーションが有効にならないので、地道に手作業でgetter/setterを作成してアノテーションをつけないと行けません。
また、case classにしておくと勝手にequalsやhashCode関数をオーバーライドしてくれるので便利ですが、引数なしのコンストラクタもあわせて定義しておいてあげましょう。
NG
import scala.reflect.BeanProperty import com.amazonaws.services.dynamodb.datamodeling._ case class Hoge( @BeansInfo @DynamoDBHashKey(attributeName="Id") var id : Long, @BeansInfo var nickname : String){ def this() = this(0,"") }
OK
import scala.reflect.BeanProperty import com.amazonaws.services.dynamodb.datamodeling._ case class Hoge(var id : Long, @BeansInfo var nickname : String){ def this() = this(0,"") @DynamoDBHashKey(attributeName="Id") def getId() : Long = id def setId(id : Long) = this.id = id; }
5. O/R Mapper時にクラスの継承を行うと変数が上手くマップされない
幾つかのテーブルが同じようなテーブルで同じ変数持ってるから、継承で共通化しちゃえと思って継承を使ってみたところ、上手くO/R Mapperがフィールドをマップしてくれませんでした。
回避方法は、「継承元のクラスにDynamoDBTableアノテーションを付ける」になります。
NG
class Hoge(... , var hoge : String){ def this() = this(...) ... def getHoge():String = hoge def setHoge( hoge : String){ this.hoge = hoge} } @DynamoDBTable(tableName="FugaTable") class Fuga extends Hoge
OK
@DynamoDBTable(tableName="DummyAnnotation") //<- これ重要 class Hoge ... @DynamoDBTable(tableName="FugaTable") class Fuga extends Hoge
ちなみに、こうなっちゃう原因はDynamoDBRefrector@isRelevantGetter(DynamoDBRefrector.java:92)の
private boolean isRelevantGetter(Method m) { return (m.getName().startsWith("get") || m.getName().startsWith("is")) && m.getParameterTypes().length == 0 && m.getDeclaringClass().getAnnotation(DynamoDBTable.class) != null && !m.isAnnotationPresent(DynamoDBIgnore.class); }で、メソッドのDeclaringClassのアノテーションを取ってしまっちゃってるからです。
2012年5月11日金曜日
pythonでファイルやディレクトリを列挙 まとめ
指定したディレクトリのすべてのファイルとディレクトリを列挙
import os for onlyFilename in os.listdir("mydir"): print onlyFilename -------------------- 'dir1' 'dir2' 'file1.txt' 'file2.txt' 'file2.py'常にファイル、ディレクトリ名だけを返します。
特定の拡張子のファイルだけを列挙
import glob for filenameWithPathAsString in glob.glob("mytexts/*.txt"): print absFilePathAsString -------------------- 'mytexts/hoge.txt' 'mytexts/wahoo.txt' ...出力には、指定したPathも付けられています
ディレクトリのみを列挙
import glob import os import os.path for filename in glob.glob("mydir/*"): if os.path.isdir(filename): print filename -------------------- 'mydir/dir1' 'mydir/dir2' ...
再帰的に全てのファイル、ディレクトリを列挙
for path,dirs,files in os.walk("mydir"): print path,dirs,files深さ優先でディレクトリを掘って行きます。 例
"." -> "./dir1" -> "./dir1/hoge" -> "./dir2" -> "./dir2/hoge"
2012年4月24日火曜日
specs2で並列テストをOffにする
ありがた迷惑な機能として、specs2ではテスト実行時に自動で並列実行してくれます。
テスト実行は早くなりますが、DBの絡んだテストやファイルの絡んだテストでは問題になることも多々あります。
ただし、次のようにするだけで簡単に逐次実行に変更可能なので並列テストでの問題が出た場合は試してみてください。
import scala.specs2.Specification // or import scala.specs2.mutable.Specification class MediaProxyTest extends Specification{ sequencial // <- この1行を付けるだけ /* test codes +/ }