Naoki Kurosawa
naoki_kuros****@ybb*****
2003年 4月 3日 (木) 21:14:16 JST
黒澤です。 ロボットが作成したデータのやり取り方法の案です。 ご意見よろしくお願いします。 まず、1つのロボットの対戦を複数のサーバが同時に実行してしまうと、 同時に上がってくるデータのどれを残すのか判断できなくなってしまう、 というお話はしたと思います。 以前この話をしたときは1リーグ内での話でしたが、 1on1とmeleeなど、1つのロボットが複数リーグに同時に参加するので、 リーグ間でもデータ更新の競合が起きないよう考慮する必要があります。 これを解決するのために、ロボットが作成したデータはリーグごとに 独立して保存・やり取りするのがいいと思います。 つまり、あるロボットが1on1とmeleeの2つのリーグに属しているとき、 1on1のリーグで対戦したときに作成したデータと meleeのリーグで対戦したときに作成したデータは 別に管理されるということです。 #同じリーグなら、シーズン間では引き続きデータを利用できます。 それでは実装案。 ■データ格納領域 JBOSS_HOME直下などにデータ格納用のルートディレクトリ (ここでは例としてrobot_data)を作ります。 そして、ルートの下にはleague_idを名前としたサブディレクトリを作ります。 ロボットのデータはこのサブディレクトリの下に、 robot_version_idまたはJARファイル名を名前とした (つまり、ロボット名とバージョンが区別される名前) サブディレクトリを作って、その中に格納します。 例えば、リーグ1に ・robotA ver1.0 ・robotA ver1.1 ・robotB ver1.0 が所属していたとすると、 JBOSS_HOME/robot_data/1/ robotA_1.0.jar/ robotA_1.1.jar/ robotB_1.0.jar/ というディレクトリ構成になります。 各ロボットのディレクトリを作成するタイミングは、 ロボット登録終了後、JARファイル内に最初からデータが含まれているときか、 Robotがデータを作った後です。 また、分散サーバ側にも同じ構成でディレクトリを作ります。 ここで作成したディレクトリと、Robocodeの.robotcacheの下にできる ロボットデータ格納用ディレクトリを区別するため、 「分散サーバのロボットデータディレクトリ」と、 「.robotcacheのロボットデータディレクトリ」というように呼び分けます。 ■通信用クラス ○FileDataSpecを新設 FileDataSpec { String name; int size; long time; } 中央サーバから取得するファイルを指定するときや、 中央サーバ上から削除するファイルを指定するときに使います。 ○RobotSpecを変更 対戦情報取得時に使用されるRobotSpecクラスに、 データファイル一覧を渡すためのメンバとして FileDataSpecの配列を追加します。 ○DownloadFilesを新設 中央サーバからダウンロードしたいファイルを指定するときに使います。 DownloadFiles { int robot_version_id; FileDataSpec[] files; //取得したいファイルの一覧 } 1つのロボットにつきDownloadFilesのインスタンスを1つ使います。 ○RobotDataを新設 ロボットデータダウンロード/アップロード時に使います。 RobotData { int robot_version_id; byte[] data; // 転送したいファイルをすべてZIP圧縮したもの FileDataSpec[] deleteFiles; // 削除したいファイルの一覧 } deleteFilesは対戦結果転送時のみ使い、対戦を行った結果削除された ファイルがあったら、中央サーバ上でも削除するように指示します。 ○BattleResultSetの変更 対戦した結果削除されたファイルの一覧と、新規作成/更新されたファイルを 中央サーバに送信するため、 BattleResultSetにRobotDataの配列を追加します。 ■対戦情報取得時 対戦情報取得時、中央サーバはロボットのデータディレクトリをサーチして ファイル一覧を作成し、FileDataSpecの配列としてRobotSpecにセットして 分散サーバに渡します。 ロボットのディレクトリがないときはnullにしておきます。 分散サーバは対戦情報取得後、バトルを開始する前に FileDataSpecの配列をチェックします。 ・nullなら何もしない もしくは、分散サーバのロボットデータディレクトリが存在したら消す。 ・nullでないなら分散サーバのロボットデータディレクトリと比較して、 データ同期処理(下り)に入ります。 ■データ同期処理(下り) 分散サーバのロボットデータディレクトリが存在しないときは 作成します。 中央サーバから取得したファイル一覧と、 ロボットデータディレクトリを比較して、 ・ローカルにあるが、ファイル一覧に載っていないものは削除 ・ファイル一覧に載っているがローカルにないもの、 もしくは、ファイル一覧に載っている方が新しいものについては、 ファイルを取得 □ファイルの取得方法 Webサービスでやります。 #Webサービスでやると、バイナリをやり取りするときBASE64エンコーディング #しなければならないので通信量が増えますが、やり取りの内容が複雑なので #仕方ない、とします。 GetRobotDataサービスをつくり、サーバ側受け口とします。 getメソッドを作ります。 パラメータは、 ・分散サーバのhostname ・分散サーバのpassword ・league_id ・DownloadFilesクラスの配列 分散サーバは、1division分のバトル情報を取得しているので、 そのdivisionに属するロボット1台につきDownloadFilesを1つ作り、 その配列を送信することで、一気に1division分のデータを取得しようとします。 で、 GetRobotDataはhostnameとpasswordで認証した後、 RobotDataの配列を返します。 このとき、RobotData#deleteFilesメンバはnullです。 RobotDataの配列を取得した分散サーバは、 分散サーバのロボットデータディレクトリに上書きで展開します。 ■バトルの実行方法 バトルの実行時は、.robotcacheのロボットデータディレクトリの中身を いったん消し、分散サーバのロボットデータディレクトリの内容を コピーしてからRobocodeを起動します。 ■対戦結果の送信時 分散サーバのロボットデータディレクトリと .robotcacheのロボットデータディレクトリの中身を比較し、 RobotDataの配列を作成します。 1つのロボットに1つRobotDataを作成し、以下の情報をセットします。 ・削除されたファイルの一覧をRobotDataのdeleteFilesメンバに設定 ・更新されたファイルをZIP圧縮し、dataメンバに設定 BattleResultSetにRobotDataの配列を格納して送信します。 また、分散サーバのロボットデータディレクトリの中身をいったん消し、 .robotcacheのロボットデータディレクトリをコピーしておきます。 RobotDataの配列を受け取った中央サーバは、 削除指示と更新データを反映させます。 以上です。 ※※データ量管理をしていないロボットを救うには※※ ロボットデータ領域は200KBまでという制限がRobocodeにはありますが、 #クォータと呼ぶことにします。 ジャパンカップに応募されたロボットの中には、 ランクわけなしのリーグ戦を行う前提でできていないものがあります。 つまり、データ量が200KBまで行かないことがあらかじめわかっているために、 作ったデータで不要なものを削除する仕組みを持っていない ロボットがあるということです。 これを救うには、たとえばクォータの90%までデータが増えたら、 古いファイルを削除する機能を付けることが考えられますが、 一方、更新しない初期データを持ち、対戦を行うごとにデータが増えていく タイプのRobotがあると、お掃除機能が初期データを削除してしまって 動作しなくなることが考えられます。 どちらも救おうとすると、 お掃除機能のON/OFFとデータ削除の閾値をユーザに設定してもらうことが 考えられますが、ちと面倒でもあります。 皆さんのご意見はいかがでしょうか。 ちなみに、お掃除機能は分散サーバ側で動作し、 1戦やるごとに起動する必要があると思われます。 -- Naoki Kurosawa <naoki_kuros****@ybb*****>