2009-03-31 16 views
1

私は個人的に.net分散キャッシュソリューションをコミットしていますが、この質問はすべてのプラットフォームで面白いと思います。分散キャッシュ内の "実"オブジェクト参照?

キャッシュ間に参照の整合性を維持しながらオブジェクトをキャッシュに格納できる分散キャッシングソリューション(または汎用戦略)がありますか?

例 - オブジェクトBar barを参照するオブジェクトFoo fooと、そのオブジェクトを参照するオブジェクトFoo foo2が同じBar barを持つとします。 fooをキャッシュにロードすると、barのコピーがキャッシュに格納されます。 foo2もキャッシュにロードすると、barの別のコピーがキャッシュに格納されます。私はキャッシュにfoo.barを変更すると、変更は影響しませんfoo2.bar :(

foo.barfoo2.barの参照を維持しながら、キャッシュにfoofoo2barをロードするために私を可能にする、既存の分散キャッシュソリューションはありますか?

答えて

3

まず第一に

私は、任意の分散システムを知らない、と私は1つを構築するふりをするつもりはありません。この投稿は、あなたがIObjectReference INTEを使用して.NETとC#で、この動作をシミュレートする方法について説明直列化可能なオブジェクトを持つrface。

は今、私は、このような分散システムを知りませんが、あなたはやや簡単IObjectReferenceインタフェースを使用して.NETでこれをachiveできるショー

で上に行くことができます。 ISerializable.GetObjectDataの実装では、SerializationInfo.SetTypeを呼び出して、IObjectReferenceを実装するプロキシクラスを指摘し、GetObjectDataメソッドによって提供されるデータの助けを借りて、使用されるべき実際のオブジェクトへの参照を取得できるようにする必要があります。

例コード:

[Serializable] 
internal sealed class SerializationProxy<TOwner, TKey> : ISerializable, IObjectReference { 
    private const string KeyName = "Key"; 
    private const string InstantiatorName = "Instantiator"; 
    private static readonly Type thisType = typeof(SerializationProxy<TOwner, TKey>); 
    private static readonly Type keyType = typeof(TKey); 

    private static readonly Type instantiatorType = typeof(Func<TKey, TOwner>); 
    private readonly Func<TKey, TOwner> _instantiator; 
    private readonly TKey _key; 

    private SerializationProxy() { 
    } 

    private SerializationProxy(SerializationInfo info, StreamingContext context) { 
     if (info == null) throw new ArgumentNullException("info"); 

     _key = (TKey)info.GetValue(KeyName, keyType); 
     _instantiator = (Func<TKey, TOwner>)info.GetValue(InstantiatorName, instantiatorType); 
    } 

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { 
     throw new NotSupportedException("This type should never be serialized."); 
    } 

    object IObjectReference.GetRealObject(StreamingContext context) { 
     return _instantiator(_key); 
    } 

    internal static void PrepareSerialization(SerializationInfo info, TKey key, Func<TKey, TOwner> instantiator) { 
     if (info == null) throw new ArgumentNullException("info"); 
     if (instantiator == null) throw new ArgumentNullException("instantiator"); 

     info.SetType(thisType); 
     info.AddValue(KeyName, key, keyType); 
     info.AddValue(InstantiatorName, instantiator, instantiatorType); 
    } 
} 

このコードは、あなたのGetObjectDataメソッドからSerializationProxy.PrepareSerialization(情報、MYKEY、MYKEY => LoadedInstances.GetById(MYKEY))と呼ばれることになる、とあなたLoadedInstances.GetByIdを返す必要がありますDictionary < TKey、WeakReference >からインスタンスを取得するか、既に読み込まれていない場合はcache/databaseから読み込みます。

EDIT:

私は私が何を意味するかを示すために、いくつかのサンプルコードを書いてきました。

public static class Program { 
    public static void Main() { 
     // Create an item and serialize it. 
     // Pretend that the bytes are stored in some magical 
     // domain where everyone lives happily ever after. 
     var item = new Item { Name = "Bleh" }; 
     var bytes = Serialize(item); 

     { 
      // Deserialize those bytes back into the cruel world. 
      var loadedItem1 = Deserialize<Item>(bytes); 
      var loadedItem2 = Deserialize<Item>(bytes); 

      // This should work since we've deserialized identical 
      // data twice. 
      Debug.Assert(loadedItem1.Id == loadedItem2.Id); 
      Debug.Assert(loadedItem1.Name == loadedItem2.Name); 

      // Notice that both variables refer to the same object. 
      Debug.Assert(ReferenceEquals(loadedItem1, loadedItem2)); 

      loadedItem1.Name = "Bluh"; 
      Debug.Assert(loadedItem1.Name == loadedItem2.Name); 
     } 

     { 
      // Deserialize those bytes back into the cruel world. (Once again.) 
      var loadedItem1 = Deserialize<Item>(bytes); 

      // Notice that we got the same item that we messed 
      // around with earlier. 
      Debug.Assert(loadedItem1.Name == "Bluh"); 

      // Once again, force the peaceful object to hide its 
      // identity, and take on a fake name. 
      loadedItem1.Name = "Blargh"; 

      var loadedItem2 = Deserialize<Item>(bytes); 
      Debug.Assert(loadedItem1.Name == loadedItem2.Name); 
     } 
    } 

    #region Serialization helpers 
    private static readonly IFormatter _formatter 
     = new BinaryFormatter(); 

    public static byte[] Serialize(ISerializable item) { 
     using (var stream = new MemoryStream()) { 
      _formatter.Serialize(stream, item); 
      return stream.ToArray(); 
     } 
    } 

    public static T Deserialize<T>(Byte[] bytes) { 
     using (var stream = new MemoryStream(bytes)) { 
      return (T)_formatter.Deserialize(stream); 
     } 
    } 
    #endregion 
} 

// Supercalifragilisticexpialidocious interface. 
public interface IDomainObject { 
    Guid Id { get; } 
} 

// Holds all loaded instances using weak references, allowing 
// the almighty garbage collector to grab our stuff at any time. 
// I have no real data to lend on here, but I _presume_ that this 
// wont be to overly evil since we use weak references. 
public static class LoadedInstances<T> 
    where T : class, IDomainObject { 

    private static readonly Dictionary<Guid, WeakReference> _items 
     = new Dictionary<Guid, WeakReference>(); 

    public static void Set(T item) { 
     var itemId = item.Id; 
     if (_items.ContainsKey(itemId)) 
      _items.Remove(itemId); 

     _items.Add(itemId, new WeakReference(item)); 
    } 

    public static T Get(Guid id) { 
     if (_items.ContainsKey(id)) { 
      var itemRef = _items[id]; 
      return (T)itemRef.Target; 
     } 

     return null; 
    } 
} 

[DebuggerDisplay("{Id} {Name}")] 
[Serializable] 
public class Item : IDomainObject, ISerializable { 
    public Guid Id { get; private set; } 
    public String Name { get; set; } 

    // This constructor can be avoided if you have a 
    // static Create method that creates and saves new items. 
    public Item() { 
     Id = Guid.NewGuid(); 
     LoadedInstances<Item>.Set(this); 
    } 

    #region ISerializable Members 
    public void GetObjectData(SerializationInfo info, StreamingContext context) { 
     // We're calling SerializationProxy to call GetById(this.Id) 
     // when we should be deserialized. Notice that we have no 
     // deserialization constructor. Fxcop will hate us for that. 
     SerializationProxy<Item, Guid>.PrepareSerialization(info, Id, GetById); 
    } 
    #endregion 

    public static Item GetById(Guid id) { 
     var alreadyLoaded = LoadedInstances<Item>.Get(id); 
     if (alreadyLoaded != null) 
      return alreadyLoaded; 

     // TODO: Load from storage container (database, cache). 
     // TODO: The item we load should be passed to LoadedInstances<Item>.Set 
     return null; 
    } 
} 
+0

Simon、丁寧な返信をありがとう。私はそれが私の頭の上に少し行きました。シリアル化プロキシがオブジェクトを格納する分散キャッシュにどのように関連しているのか説明できますか? – urig