svnno****@sourc*****
svnno****@sourc*****
2008年 11月 15日 (土) 18:22:57 JST
Revision: 2147 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=jiemamy&view=rev&rev=2147 Author: ewigkeit1204 Date: 2008-11-15 18:22:57 +0900 (Sat, 15 Nov 2008) Log Message: ----------- [SER-6] Swapper で複数回取得した RealObejct 同士は参照が同一であるべき 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 -------------- next part -------------- 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 07:04:39 UTC (rev 2146) +++ artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/SwapObject.java 2008-11-15 09:22:57 UTC (rev 2147) @@ -19,12 +19,17 @@ package org.jiemamy.serializer.swap; import java.io.Serializable; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; /** - * あるオブジェクトをスワップの対象とし、管理するクラス。 + * ある RealObject をスワップの対象とし、管理するクラス。 * * <p> - * スワップされたオブジェクトは{@link SwapObject#get() }で取得できる。 + * スワップされたオブジェクトは{@link SwapObject#get() }で取得できる。<br> + * 内部では RealObject への弱参照を保持し、デシリアライズ要求を受けた際、<br> + * RealObject へ到達が可能と判断された場合は{@link Swapper }へデシリアライズ<br> + * 要求を委譲せず、到達できた RealObject を返す。 * </p> * * @author Keisuke.K @@ -32,32 +37,52 @@ */ public class SwapObject<T extends Serializable> { - /** スワップファイル内でのスワップ済みオブジェクトの位置 */ + /** スワップファイル内でのスワップ済み RealObject の位置 */ long position; - /** スワップファイル内でのスワップ済みオブジェクトのバイト長 */ + /** スワップファイル内でのスワップ済み RealObject のバイト長 */ int length; + /** スワップする RealObject への参照 */ + Reference<T> ref; + /** * コンストラクタ。 * + * <p> + * {@link Swapper }へシリアライズ要求を行う前に、RealObjectへの弱参照を保持する。 + * </p> + * * @param obj スワップの対象とするオブジェクト * @throws SwapException * @category instance creation */ public SwapObject(T obj) throws SwapException { + ref = new WeakReference<T>(obj); Swapper.INSTANCE.serialize(this, obj); } /** * スワップ済みのオブジェクトを取得する。 * + * <p> + * RealObject への弱参照が到達可能な場合、到達した RealObject を返す。<br> + * 到達できない場合は{@link Swapper }へ RealObject のデシリアライズ要求を委譲する。 + * </p> + * * @return スワップ済みのオブジェクト * @throws SwapException */ - public T get() throws SwapException { - return Swapper.INSTANCE.deserialize(this); + public synchronized T get() throws SwapException { + T obj = ref.get(); + + if (obj == null) { + obj = Swapper.INSTANCE.deserialize(this); + ref = new WeakReference<T>(obj); + } + + return 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 07:04:39 UTC (rev 2146) +++ artemis/trunk/org.jiemamy.serializer/src/main/java/org/jiemamy/serializer/swap/Swapper.java 2008-11-15 09:22:57 UTC (rev 2147) @@ -60,10 +60,10 @@ FileChannel channel; /** スワップ情報を一元管理する参照TreeSet */ - TreeSet<Reference<SwapObject<?>>> swapReferenceSet; + TreeSet<Reference<SwapObject<?>>> swapRefSet; /** スワップ情報参照キュー */ - ReferenceQueue<SwapObject<?>> queue; + ReferenceQueue<SwapObject<?>> swapRefQueue; /** @@ -81,8 +81,8 @@ throw new RuntimeException(e); } - swapReferenceSet = (new TreeSet<Reference<SwapObject<?>>>(new SetComparator())); - queue = new ReferenceQueue<SwapObject<?>>(); + swapRefSet = new TreeSet<Reference<SwapObject<?>>>(new SetComparator()); + swapRefQueue = new ReferenceQueue<SwapObject<?>>(); } /** @@ -95,16 +95,16 @@ * @throws IOException */ void clean() throws IOException { - synchronized (swapReferenceSet) { + synchronized (swapRefSet) { // 参照TreeSetのクリーニング Reference<? extends SwapObject<?>> ref; - while ((ref = queue.poll()) != null) { - swapReferenceSet.remove(ref); + while ((ref = swapRefQueue.poll()) != null) { + swapRefSet.remove(ref); } // スワップファイルのサイズ調整 - if (swapReferenceSet.size() > 0) { - SwapObject<?> swapObj = swapReferenceSet.last().get(); + if (swapRefSet.size() > 0) { + SwapObject<?> swapObj = swapRefSet.last().get(); if (swapObj != null) { synchronized (channel) { channel.truncate(swapObj.position + swapObj.length); @@ -199,24 +199,8 @@ */ <T extends Serializable>void serialize(SwapObject<T> swapObj, T obj) throws SwapException { // オブジェクトのシリアライズを行う - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = null; + ByteBuffer buffer = serialize(obj); - try { - oos = new ObjectOutputStream(baos); - oos.writeObject(obj); - } catch (IOException e) { - throw new SwapException(e); - } finally { - try { - if (oos != null) { - oos.close(); - } - } catch (IOException e) { - throw new SwapException(e); - } - } - // オブジェクトをスワップする位置を特定する try { clean(); @@ -224,9 +208,9 @@ throw new SwapException(e); } - synchronized (swapReferenceSet) { + synchronized (swapRefSet) { long pos = 0L; - for (Reference<SwapObject<?>> ref : swapReferenceSet) { + for (Reference<SwapObject<?>> ref : swapRefSet) { SwapObject<? extends Serializable> tmp = ref.get(); if (tmp == null) { @@ -234,7 +218,7 @@ continue; } - if (tmp.position - pos >= baos.size()) { + if (tmp.position - pos >= buffer.limit()) { // 位置決定 break; } @@ -243,25 +227,63 @@ } swapObj.position = pos; - swapObj.length = baos.size(); + swapObj.length = buffer.limit(); - Reference<SwapObject<?>> ref = new WeakReference<SwapObject<?>>(swapObj, queue); - swapReferenceSet.add(ref); + Reference<SwapObject<?>> ref = new WeakReference<SwapObject<?>>(swapObj, swapRefQueue); + swapRefSet.add(ref); } // スワップ - ByteBuffer buffer = ByteBuffer.wrap(baos.toByteArray()); + swap(buffer, swapObj.position); + } + + /** + * オブジェクトをシリアライズして、その結果をByteBufferで取得する。 + * + * @param obj シリアライズするオブジェクト + * @return シリアライズ結果のバイト値を保持するByteBuffer + * @throws SwapException + */ + private ByteBuffer serialize(Serializable obj) throws SwapException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = null; try { - synchronized (channel) { - channel.write(buffer, swapObj.position); - } + oos = new ObjectOutputStream(baos); + oos.writeObject(obj); } catch (IOException e) { throw new SwapException(e); + } finally { + try { + if (oos != null) { + oos.close(); + } + } catch (IOException e) { + throw new SwapException(e); + } } + + return ByteBuffer.wrap(baos.toByteArray()); } + /** + * シリアライズしたオブジェクトをスワップする。 + * @param buffer シリアライズ結果 + * @param position スワップ位置 + * @throws SwapException + */ + private void swap(ByteBuffer buffer, long position) throws SwapException { + synchronized (channel) { + try { + channel.write(buffer, position); + } catch (IOException e) { + throw new SwapException(e); + } + } + } + + /** * {@code swapReferenceSet }のための比較クラス。 * 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 07:04:39 UTC (rev 2146) +++ artemis/trunk/org.jiemamy.serializer/src/test/java/org/jiemamy/serializer/swap/SwapperTest.java 2008-11-15 09:22:57 UTC (rev 2147) @@ -19,6 +19,7 @@ package org.jiemamy.serializer.swap; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertSame; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; @@ -89,6 +90,7 @@ String str2 = "fizzbuzz"; // スワップ + @SuppressWarnings("unused") SwapObject<String> swapObj1 = new SwapObject<String>(str1); @SuppressWarnings("unused") SwapObject<String> swapObj2 = new SwapObject<String>(str2); @@ -103,13 +105,12 @@ // see. http://d.hatena.ne.jp/Ewigkeit/20080823/1219463052 Thread.sleep(1000L); - // swapObj1の取得を行うことで、スワップファイルの長さを調整させる。 - String getStr1 = swapObj1.get(); + // Swapper をクリーニング + Swapper.INSTANCE.clean(); long newSize = Swapper.INSTANCE.channel.size(); // チェック - assertEquals(str1, getStr1); assertTrue(currentSize > newSize); // [SER-5] 新しくオブジェクトをスワップさせ、NPE が発生しないことを確認。 @@ -121,4 +122,26 @@ } } + /** + * 1つのSwapObjectに対して複数回get()を行い、取得できたRealObject同士は参照が同一であるべき。 + * + * @throws Exception + */ + @Test + public void test04_複数回取得した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); + + // 取得 + HashMap<String, String> map1 = swapObj.get(); + HashMap<String, String> map2 = swapObj.get(); + + // チェック + assertSame(map1, map2); + } + }