アスペクト指向言語による 例外処理の記述方法の改善
DESCRIPTION
アスペクト指向言語による 例外処理の記述方法の改善. 数理・計算科学専攻 千葉研究室 熊原奈津子 指導教員:千葉滋. 例外処理とは 異常時の処理をまとめて記述したもの 正常時には実行されないコード ロジックとは分離して 書くべき Java には try-catch がある 分離はできるが正常時の処理のすぐ下に書かなければならない. 例外処理の分離の重要性. try { // ファイルへの操作 File file = new File(); file.open(); file.read(); file.write(); : - PowerPoint PPT PresentationTRANSCRIPT
アスペクト指向言語による例外処理の記述方法の改善
数理・計算科学専攻 千葉研究室熊原奈津子
指導教員:千葉滋
修士論文発表会 2
Chiba Shigeru Group
例外処理の分離の重要性例外処理とは
異常時の処理をまとめて記述したもの正常時には実行されないコード
ロジックとは分離して書くべき
Java には try-catch がある分離はできるが正常時の処理のすぐ下に書かなければならない
try { // ファイルへの操作 File file = new File(); file.open(); file.read(); file.write(); :
} catch(IOException e){ IOException が発生した 場合の例外処理内容}
修士論文発表会 3
Chiba Shigeru Group頻繁に例外処理を差し替えたい - 実験プログラム
分散環境で動くサーバの性能をテスト最初は小規模なので例外処理なし問題(故障)が起きたら必要に応じて追加
制御プログラ
ム
コンソールマシンの絵
コンソールマシン
クライアントマシン
命令
命令命令
サーバマシン負荷
負荷
故障
修士論文発表会 4
Chiba Shigeru Group
元のプログラムを編集class Sender{ public void sendCommand(String host, String command) throws Exception{ : Socket s = new Socket(host, port); DataOutputStream out = new DataOutputStream(s.getOutputStream()); out.write(command); out.close(); s.close();
System.out.println(command + “ has been sent to ” + host);}
クライアントに
ソケットを張る
命令を送信
try{
} catch(SocketException e){ // 故障を見つけたらログを出力 }
for (int i = 0; i < hostName.length; i++){ new Sender().sendCommand(hostName[i], “./client.sh”);}
複数のホストに
命令を送信
修士論文発表会 5
Chiba Shigeru Group他のマシンを使って再試行(リカバリ)
catch 節の中から try ブロックの先頭へ戻るホスト故障時には、自動的に復旧処理
try{ Socket s = new Socket(host, port); DataOutputStream out = new DataOutputStream( s.getOutputStream()); out.write(command); out.close(); s.close(); } catch(SocketException e) { ホストを変更して再試行 }
Java には再試行を直接実現する構文はない
修士論文発表会 6
Chiba Shigeru Group
GluonJ/R の提案 - Recover アドバイスをもつ AOP System
例外処理をアスペクトとして記述例外処理を分離
もとのロジックを壊さずに追加・削除が可能
例外処理に特化した pointcut 指定子を提供Java バイトコード変換で実現
再試行するための特殊メソッド (retry) を用意
アドバイス内で利用可能リカバリ処理を容易に記述できる
修士論文発表会 7
Chiba Shigeru GroupGluonJ/R の特徴:アスペクトとして分離
block ポイントカット指定子範囲をポイントカットできるジョインポイントのペアを指定( try ブロック指定に相当)
recover アドバイスcatch 節に相当
Socket s = new Socket( host, port);DataOutputStream out = newDataOutputStream( s.getOutputStream()); out.write(command);out.close();s.close();System.out.println(“done”);
元のプログラム アスペクト
分離して記述
@Glue class SenderRecovery { @Recover( etype = “SocketException”, advice = “{ $1 = getAnotherHost(); GluonJR.retry(); }”) Pointcut p = Pcd .block(Pcd.call(“Socket#new(..)”), Pcd.call(“PrintStream#plintln()”));}
修士論文発表会 8
Chiba Shigeru Group
GluonJ/R のプログラム例@Glue class SenderRecovery { @Refine static class Diff extends Sender{ public String getAnotherHost(){ // 他のホスト名を返す } } @Recover( etype = “SocketException”, advice = “{ $1 = getAnotherHost(); GluonJR.retry(); }”) Pointcut p = Pcd.block( Pcd.call(“Socket#new(..)”), Pcd.call(“PrintStream#plintln()”))}
例外処理を追加したい範囲を指定
アドバイス
修士論文発表会 9
Chiba Shigeru Group
GluonJ/R の特徴:再試行
Socket s = new Socket(host, port);DataOutputStream out = newDataOutputStream( s.getOutputStream()); out.write(command);out.close();s.close();System.out.println(“done”);
元のプログラム アスペクト
@Glue class SenderRecovery { @Recover( etype = “SocketException”, advice = “{ $1 = getAnotherHost(); GluonJR.retry(); }”) Pointcut p = Pcd .block(Pcd.call(“Socket#new(..)”), Pcd.call(“PrintStream#println()”));}
特殊メソッド GluonJR.retry()アドバイスの中で利用可能block で指定した範囲の先頭に戻る
修士論文発表会 10
Chiba Shigeru Group行アノテーション
ジョインポイントの一種GluonJ/R の文法拡張block による範囲指定に利
用将来指定されそうな場所に
ジョインポイントがないとき、あらかじめ書いておく
if( ・・・ ){ :} else { :}@Line(begin)for( ・・ ; ・・ ; ・・ ){ :}@Line(end) :
自由に名前がつけれる
自由に名前がつけられる
Pointcut p = Pcd.block(Pcd.line(“begin”), Pcd.line(“end”));
修士論文発表会 11
Chiba Shigeru Group
GluonJ/R の実装
GluonJ 1.3 を拡張して実装拡張は GluonJ に対するアスペクトのみで記述
GluonJ 自体は全く変更していないプラグイン同様、追加削除が容易
GluonJ の総コード数 5000 行に対して拡張部分は 400 行程度バイトコード変換には Javassist を利用
行アノテーションのプリプロセッサを用意
修士論文発表会 12
Chiba Shigeru Group
例外ハンドラの追加
クラスファイル
メソッドの情報
メソッドの属性
・・
・
・・
・
メソッドを実装しているバイトコード
Exception Table 1. 例外ハンドラがアクティブとなるバイトコードの範囲 ( 始点・終点 )
2. 例外ハンドラがキャッチする例外のクラス
3. 例外ハンドラの先頭
block で指定した範囲
1. 始点・終点(ソースコード)2. 処理したい例外の型3. 例外が生じた場合に
実行したいコード
←始点
←終点
・・
←例外ハンドラの先頭
Exception Table に含まれる情報
ユーザから与えられる情報
範囲・例外の種類・飛び先
アドバイス
修士論文発表会 13
Chiba Shigeru Group
1. GluonJ/R 内でソースコードをコンパイルし、バイトコードへ変換
2. invokestatic 命令を命令長が同じ 3 バイトの goto 命令に置換
コンパイル
GluonJR.retry() の実装
:GluonJR.retry(); : 変換
メソッドのバイトコード
アドバイス : invokestatic :
: goto :
block←始点
範囲の始点に戻る
修士論文発表会 14
Chiba Shigeru Group
範囲を選択するアルゴリズム
始点・終点が同一メソッド内に存在
最も近いペア(始点・終点)を選択
始点となるソースコードが実行される直前から終点となるソースコードが実行される直前までを選択
foo(); :foo(); :hoge();bar(); :bar();
block
始点候補 終点候補
Pointcut p = Pcd.block( Pcd.call(“foo(..)”), Pcd.call(“bar(..)”));
修士論文発表会 15
Chiba Shigeru Group実装の要点:block で指定する範囲の始点
ジョインポイント・シャドーではないジョインポイントに直接対応するバイトコード命令ではない
Invokevirtual, getfield 等
その命令を含むソースコード行の最初のバイトコード命令
retry() の実現のためアドバイス内から goto で戻っても bytecode verifier をパスする
new Socketdupaload_1iload 4invokespecial Socket()astore 5
Socket s = new Socket(host, port);
コンパイルJP Shadow
先頭の命令
修士論文発表会 16
Chiba Shigeru Group
JVM のスタックの状態遷移図
retry() で戻ってくる
invokespecial
スタックは空の状態
ref
ref
ref
ref
ref
new int
str
dup ・・・・・
×○
new Socketdupaload_1iload 4invokespecial Socket()astore 5
Socket s = new Socket(host, port); コンパイル
例
修士論文発表会 17
Chiba Shigeru Group行アノテーションのプリプロセッサプリプロセッサで空
のスタティックメソッド呼び出しに変換
プログラムの挙動には影響なし
性能に対する影響については後述
if( ・・・ ){ :} else { :}@Line(begin)for( ・・ ; ・・ ; ・・ ){ :}@Line(end) :
LineAnnotation.begin();
LineAnnotation.end();
class LineAnnotation{ public static void begin(){} public static void end(){}}
修士論文発表会 18
Chiba Shigeru Group
現在の実装の限界
異なるブロックをまたぐ範囲の選択メソッドをまたぐ範囲は選択できないfor 、 while 文等のブロックをまたいでも選択可能
finally 節の扱い選択範囲外の finally 節が範囲に含まれてしまう可能性がある(コンパイラによる)Recover アドバイス内で例外を投げると、元の finally 節が無視される
修士論文発表会 19
Chiba Shigeru Group
finally 節に関する問題try { :
} catch (){ :} finally { :}
try {
: :
} catch (){ :} finally { :}
例1 例2 例 3try { : if ( ・・ ){ return; } :
} catch (){ :} finally { (finally 節 )}
追加した方の優先順位が高いため finally 節が実行されない
展開された finally 節も含んでしまう
finally 節が実行されない
例外発生
アドバイス
アドバイス throw e;
修士論文発表会 20
Chiba Shigeru Group
実験について
実験環境CPU : Intel Pentium 4 CPU 2.8GHz
メモリ : 1GB
OS : Microsoft Windows XP Professional SP2
JVM バージョン : 1.5.0_06
目的GluonJ/R で例外処理をアスペクトとして追加した場合のオーバーヘッドを測定
修士論文発表会 21
Chiba Shigeru Group実験: try-catch 文との実行速度の比較
メソッド m() を 10億回
try-catch 文を追加アスペクトをウィーブ
public class Test { public void m() throws Exception{
a();
b(); } public void a() throws Exception{} public void b() {}}
try{
} catch(Exception e){}
@Glue class InsertTryCatch { @Recover(etype = "java.lang.Exception", advice = "") Pointcut p = Pcd.block(Pcd.call("test.Test#a(..)"), Pcd.call("test.Test#b(..)"));}
実行時間(秒)
例外処理なし 2.6
try-catch 文 17.0
GluonJ/R 17.0
修士論文発表会 22
Chiba Shigeru Group実験:行アノテーションの性能実験
public class Test { public void m() throws Exception{ @Line(begin) a(); @Line(end) b(); } public void a() throws Exception{} public void b() {}}
@Glue class InsertTryCatch { @Recover(etype = "java.lang.Exception", advice = "") Pointcut p = Pcd.block(Pcd.line("begin"), Pcd.line("end"));}
実行時間(秒)
行アノテーションなし
2.6
行アノテーション追加(例外処理なし)
2.6
行アノテーション追加(例外処理追加)
17.1
修士論文発表会 23
Chiba Shigeru Group
AspectJ との比較handler ポイントカット既に try-catch 文がプログラムに含まれている場合、catch 節の実行時をジョインポイントとして選択
after throwing アドバイス選択されたジョインポイントが例外を投げて異常終了した場合に実行される例外を補足する範囲の粒度がメソッドボディ
Java の throws も同様の問題リカバリ処理の実装には使えない
最後に必ず例外を投げなければならない
修士論文発表会 24
Chiba Shigeru Group
関連研究Eiffel や Ruby の retry 機構
Java には存在しなかった
範囲を選択するポイントカットループ処理のためのジョインポイント[Harbulot ら ‘ 06]
for 文等のブロック全体をポイントカットポイントカットできないループも数多く存在
block ポイントカットと行アノテーションは任意の範囲を選択可能
修士論文発表会 25
Chiba Shigeru Group
まとめ・今後の課題GluonJ/R
例外処理をロジックと分離して記述可能範囲をポイントカットできる pointcut 指定子
容易にリカバリできるアドバイスの中で再試行可能なメソッド
オーバーヘッドはほとんどなし
今後の課題現実のアプリケーションに適用
うまく記述できるかコードサイズをどのくらい減らすことができるか