アスペクト指向言語による 例外処理の記述方法の改善

Preview:

DESCRIPTION

アスペクト指向言語による 例外処理の記述方法の改善. 数理・計算科学専攻 千葉研究室 熊原奈津子 指導教員:千葉滋. 例外処理とは 異常時の処理をまとめて記述したもの 正常時には実行されないコード ロジックとは分離して 書くべき Java には try-catch がある 分離はできるが正常時の処理のすぐ下に書かなければならない. 例外処理の分離の重要性. try { // ファイルへの操作 File file = new File(); file.open(); file.read(); file.write(); : - PowerPoint PPT Presentation

Citation preview

アスペクト指向言語による例外処理の記述方法の改善

数理・計算科学専攻 千葉研究室熊原奈津子

指導教員:千葉滋

修士論文発表会 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 指定子

容易にリカバリできるアドバイスの中で再試行可能なメソッド

オーバーヘッドはほとんどなし

今後の課題現実のアプリケーションに適用

うまく記述できるかコードサイズをどのくらい減らすことができるか

Recommended