svnno****@sourc*****
svnno****@sourc*****
2008年 11月 16日 (日) 00:29:40 JST
Revision: 2148 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=jiemamy&view=rev&rev=2148 Author: ewigkeit1204 Date: 2008-11-16 00:29:39 +0900 (Sun, 16 Nov 2008) Log Message: ----------- RealObject の更新をサポート。 参照到達可能性の確認をスレッドにした。 Modified Paths: -------------- artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/SwapObject.java artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/Swapper.java artemis/trunk/org.jiemamy.serializer/src/test/java/org/jiemamy/serializer/swap/SwapperTest.java Added Paths: ----------- artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceListener.java artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceQueueMonitor.java -------------- next part -------------- Added: artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceListener.java =================================================================== --- artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceListener.java (rev 0) +++ artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceListener.java 2008-11-15 15:29:39 UTC (rev 2148) @@ -0,0 +1,38 @@ +/* + * Copyright 2007-2008 MIYAMOTO Daisuke, jiemamy.org and the Others. + * Created on 2008/11/16 + * + * This file is part of Jiemamy. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.jiemamy.serializer.swap; + +import java.lang.ref.Reference; + +/** + * 参照リスナ + * + * @author Keisuke.K + */ +interface ReferenceListener { + + /** + * 参照の到達可能性が変更されたことを通知する。 + * + * @param <T> 参照先のクラス型 + * @param ref 到達可能性が変更された参照 + */ + <T>void modifiedReference(Reference<T> ref); + +} Property changes on: artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceListener.java ___________________________________________________________________ Name: svn:mime-type + text/plain Added: artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceQueueMonitor.java =================================================================== --- artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceQueueMonitor.java (rev 0) +++ artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceQueueMonitor.java 2008-11-15 15:29:39 UTC (rev 2148) @@ -0,0 +1,94 @@ +/* + * Copyright 2007-2008 MIYAMOTO Daisuke, jiemamy.org and the Others. + * Created on 2008/11/15 + * + * This file is part of Jiemamy. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.jiemamy.serializer.swap; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 参照キュー監視スレッド。 + * + * <p> + * 指定された参照キューを監視し、到達可能性が変更された際に{@link ReferenceListener }を実装した<br> + * クラスに対し通知を行う。 + * </p> + * + * @param <T> 参照キューに指定する型 + * @author Keisuke.K + */ +final class ReferenceQueueMonitor<T> implements Runnable { + + private static Logger logger = LoggerFactory.getLogger(ReferenceQueueMonitor.class); + + /** 参照キュー */ + ReferenceQueue<T> queue; + + /** 参照リスナリスト */ + List<ReferenceListener> listeners; + + /** スレッド実行フラグ */ + boolean running; + + + /** + * コンストラクタ。 + * + * @param queue 監視する参照キュー + * @category instance creation + */ + public ReferenceQueueMonitor(ReferenceQueue<T> queue) { + this.queue = queue; + this.listeners = new ArrayList<ReferenceListener>(); + this.running = true; + } + + /** + * {@inheritDoc} + */ + public void run() { + while (running) { + try { + Reference<? extends T> ref = queue.remove(); + + for (ReferenceListener listener : listeners) { + listener.modifiedReference(ref); + } + } catch (InterruptedException e) { + // スレッド停止 + logger.info("Shutting down because throwing InterruptedException.", e); + running = false; + } + } + } + + /** + * 参照リスナを追加する。 + * + * @param listener 参照リスナ + */ + void addReferenceListener(ReferenceListener listener) { + listeners.add(listener); + } + +} Property changes on: artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/ReferenceQueueMonitor.java ___________________________________________________________________ Name: svn:mime-type + text/plain Modified: artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/SwapObject.java =================================================================== --- artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/SwapObject.java 2008-11-15 09:22:57 UTC (rev 2147) +++ artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/SwapObject.java 2008-11-15 15:29:39 UTC (rev 2148) @@ -32,6 +32,10 @@ * 要求を委譲せず、到達できた RealObject を返す。 * </p> * + * <p> + * また、スワップしている RealObject の内容が変わった場合、必ず{@link SwapObject#update(Serializable) }を呼ぶ必要がある。 + * </p> + * * @author Keisuke.K * @param <T> スワップの対象なるオブジェクトのクラス */ @@ -85,4 +89,21 @@ return obj; } + /** + * スワップする RealObject を引数の内容で更新する。 + * + * <p> + * スワップしている RealObject の更新は{@link Swapper }が検知することができないため、<br> + * RealObject が更新され、そのオブジェクトをスワップ情報にも更新しなければならない場合は<br> + * 必ずこのメソッドを呼ぶ必要がある。 + * </p> + * + * @param obj 更新する RealObject + * @throws SwapException + */ + public synchronized void update(T obj) throws SwapException { + ref = new WeakReference<T>(obj); + Swapper.INSTANCE.reserialize(this, obj); + } + } Modified: artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/Swapper.java =================================================================== --- artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/Swapper.java 2008-11-15 09:22:57 UTC (rev 2147) +++ artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/Swapper.java 2008-11-15 15:29:39 UTC (rev 2148) @@ -30,6 +30,9 @@ import java.util.Comparator; import java.util.TreeSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * スワップ処理を行うクラス。 * @@ -45,7 +48,7 @@ * * @author Keisuke.K */ -final class Swapper { +final class Swapper implements ReferenceListener { /** スワップファイルの接頭辞 */ static final String SWAP_FILE_PREFIX = "jiemamy"; @@ -56,6 +59,8 @@ /** シングルトンインスタンス */ static final Swapper INSTANCE = new Swapper(); + private static Logger logger = LoggerFactory.getLogger(Swapper.class); + /** スワップファイルの読み書きを行うファイルチャネル */ FileChannel channel; @@ -65,6 +70,9 @@ /** スワップ情報参照キュー */ ReferenceQueue<SwapObject<?>> swapRefQueue; + /** スワップ情報参照キュー監視スレッド */ + ReferenceQueueMonitor<SwapObject<?>> swapRefQueueMonitor; + /** * コンストラクタ。 @@ -83,6 +91,12 @@ swapRefSet = new TreeSet<Reference<SwapObject<?>>>(new SetComparator()); swapRefQueue = new ReferenceQueue<SwapObject<?>>(); + swapRefQueueMonitor = new ReferenceQueueMonitor<SwapObject<?>>(swapRefQueue); + swapRefQueueMonitor.addReferenceListener(this); + + Thread t = new Thread(swapRefQueueMonitor, "SwapObjectReferenceQueueMonitor"); + t.setDaemon(true); + t.start(); } /** @@ -91,47 +105,49 @@ * <p> * 参照の切れたスワップ情報を持ち続ける必要はない上、参照が切れているのでスワップファイルに情報を持つ必要がなくなるため。 * </p> - * - * @throws IOException */ - void clean() throws IOException { + public <T>void modifiedReference(Reference<T> ref) { synchronized (swapRefSet) { // 参照TreeSetのクリーニング - Reference<? extends SwapObject<?>> ref; - while ((ref = swapRefQueue.poll()) != null) { - swapRefSet.remove(ref); - } + swapRefSet.remove(ref); // スワップファイルのサイズ調整 if (swapRefSet.size() > 0) { SwapObject<?> swapObj = swapRefSet.last().get(); if (swapObj != null) { synchronized (channel) { - channel.truncate(swapObj.position + swapObj.length); + try { + channel.truncate(swapObj.position + swapObj.length); + } catch (IOException e) { + logger.error("Error truncating swap file channel.", e); + } } } + } else { + synchronized (channel) { + try { + channel.truncate(0L); + } catch (IOException e) { + logger.error("Error truncating swap file channel.", e); + } + } } } } /** - * 引数{@code obj }に指定されたオブジェクトをスワップファイルへシリアライズする。 + * 引数{@code swapObj }に指定されたスワップ情報を元に RealObject をデシリアライズする。 * - * <p> - * オブジェクトがシリアライズされたオフセット値、およびバイト長は引数{@code swapObj }の各フィールドに代入される。 - * </p> - * - * @param <T> 取得するスワップ済みオブジェクトのクラス。 + * @param <T> 取得するスワップ済み RealObject のクラス。 * @param swapObj スワップ位置情報を保持している{@link SwapObject }インスタンス。 - * @return スワップ済みオブジェクト + * @return スワップ済み RealObject * @throws SwapException */ @SuppressWarnings("unchecked") <T extends Serializable>T deserialize(SwapObject<T> swapObj) throws SwapException { - try { - clean(); - } catch (IOException e) { - throw new SwapException(e); + if (!swapRefSet.contains(new WeakReference(swapObj))) { + // 管理されているSwapObjectではない + throw new SwapException("Unknown swap info."); } ByteBuffer buffer = ByteBuffer.allocate(swapObj.length); @@ -186,15 +202,33 @@ } /** - * 引数{@code obj }に指定されたオブジェクトをスワップファイルへシリアライズする。 + * 引数{@code obj }に指定された RealObject をスワップファイルへシリアライズする。 * * <p> - * オブジェクトがシリアライズされた位置、およびバイト長は引数{@code swapObj }の各フィールドに代入される。 + * {@code Swapper#serialize(SwapObject, Serializable) }との違いは、<br> + * 対象の RealObject のシリアライズが初回ではなく、更新を意味することである。 * </p> * + * @param <T> スワップ対象となる RealObject のクラス。 + * @param swapObj スワップ位置情報を代入させる{@link SwapObject }インスタンス。 + * @param obj スワップ対象となる RealObject + * @throws SwapException + */ + <T extends Serializable>void reserialize(SwapObject<T> swapObj, T obj) throws SwapException { + swapRefSet.remove(new WeakReference<SwapObject<?>>(swapObj)); + serialize(swapObj, obj); + } + + /** + * 引数{@code obj }に指定された RealObject をスワップファイルへシリアライズする。 + * + * <p> + * RealObject がシリアライズされた位置、およびバイト長は引数{@code swapObj }の各フィールドに代入される。 + * </p> + * * @param <T> スワップ対象となるオブジェクトのクラス。 * @param swapObj スワップ位置情報を代入させる{@link SwapObject }インスタンス。 - * @param obj スワップ対象となるオブジェクト + * @param obj スワップ対象となる RealObject * @throws SwapException */ <T extends Serializable>void serialize(SwapObject<T> swapObj, T obj) throws SwapException { @@ -202,19 +236,13 @@ ByteBuffer buffer = serialize(obj); // オブジェクトをスワップする位置を特定する - try { - clean(); - } catch (IOException e) { - throw new SwapException(e); - } - synchronized (swapRefSet) { long pos = 0L; for (Reference<SwapObject<?>> ref : swapRefSet) { SwapObject<? extends Serializable> tmp = ref.get(); if (tmp == null) { - // [SER-5] clean()後もnullオブジェクトが残る可能性がある。remove()はclean()に一元化するため、無視する。 + // [SER-5] nullオブジェクトが残っている可能性がある。 continue; } Modified: artemis/trunk/org.jiemamy.serializer/src/test/java/org/jiemamy/serializer/swap/SwapperTest.java =================================================================== --- artemis/trunk/org.jiemamy.serializer/src/test/java/org/jiemamy/serializer/swap/SwapperTest.java 2008-11-15 09:22:57 UTC (rev 2147) +++ artemis/trunk/org.jiemamy.serializer/src/test/java/org/jiemamy/serializer/swap/SwapperTest.java 2008-11-15 15:29:39 UTC (rev 2148) @@ -105,9 +105,6 @@ // see. http://d.hatena.ne.jp/Ewigkeit/20080823/1219463052 Thread.sleep(1000L); - // Swapper をクリーニング - Swapper.INSTANCE.clean(); - long newSize = Swapper.INSTANCE.channel.size(); // チェック @@ -144,4 +141,28 @@ assertSame(map1, map2); } + /** + * スワップ後に取得したRealObjectに対して更新を行い、再度スワップ処理を行う流れのテスト。 + * + * @throws Exception + */ + @Test + public void test05_スワップ後取得したRealObjectの更新をして再度スワップ処理() throws Exception { + HashMap<String, String> testMap = new HashMap<String, String>(); + testMap.put("foo", "bar"); + testMap.put("fizz", "buzz"); + + // スワップ + SwapObject<HashMap<String, String>> swapObj = new SwapObject<HashMap<String, String>>(testMap); + + // 内容の変更 + testMap.put("John", "Doe"); + swapObj.update(testMap); + + // 取得 + HashMap<String, String> getMap = swapObj.get(); + + assertEquals(testMap, getMap); + } + }