2009-03-31 11 views
1

Ich bin persönlich verpflichtet, .net verteilte Caching-Lösungen, aber ich denke, diese Frage ist auf allen Plattformen interessant."Real" Objektverweise im verteilten Cache?

Gibt es eine verteilte Caching-Lösung (oder generische Strategie), die es ermöglicht, Objekte im Cache zu speichern, während die Integrität der Referenzen zwischen ihnen erhalten bleibt?

Zur Veranschaulichung - Angenommen, ich habe ein Objekt, die Foo fooBar bar ein Objekt verweist, und auch und Objekt Foo foo2, das die gleichen Bar bar verweist. Wenn ich foo in den Cache lade, wird eine Kopie von bar mitgespeichert. Wenn ich auch foo2 in den Cache lade, wird eine separate Kopie von bar zusammen mit diesem gespeichert. Wenn ich foo.bar im Cache zu ändern, wird die Änderung nicht foo2.bar :(

Gibt es eine bestehende verteilten Cache-Lösung auswirken, die es mir ermöglichen foo, foo2 und bar in den Cache zu laden, während die foo.barfoo2.bar Referenzen beibehalten?

Antwort

3

In erster Linie

ich weiß nicht, von jedem verteilten System, und ich will nicht behaupten, zu bauen. Dieser Beitrag wird erläutert, wie Sie dieses Verhalten mit .NET und C# simulieren können den IObjectReference inte mit rface mit serialisierbaren Objekten.

Jetzt fangen wir mit der Show weitergehen

Ich weiß nicht, von einem solchen verteilten System, aber Sie können etwas leicht diese achive mit .NET die IObjectReference Schnittstelle. Ihre Implementierung von ISerializable.GetObjectData müsste SerializationInfo.SetType aufrufen, um auf eine Proxyklasse hinzuweisen, die IObjectReference implementiert, und in der Lage wäre (mit Hilfe der von Ihrer GetObjectData-Methode bereitgestellten Daten), einen Verweis auf das reale Objekt zu erhalten, das verwendet werden sollte.

Beispielcode:

[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); 
    } 
} 

Dieser Code würde mit SerializationProxy.PrepareSerialization (info, myKey, myKey => LoadedInstances.GetById (myKey)) von Ihrem GetObjectData Methode und Ihre LoadedInstances.GetById sollte aufgerufen werden, zurückkehren die Instanz aus einem Dictionary < TKey, WeakReference > oder laden Sie es aus Cache/Datenbank, wenn es nicht bereits geladen ist.

EDIT:

Ich habe schrieb einige Beispiel-Code zu zeigen, was ich meine.

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, danke für die ausführliche Antwort. Ich fürchte, es ging ein bisschen über meinen Kopf. Können Sie erklären, wie sich der Serialisierungs-Proxy auf den verteilten Cache bezieht, in dem ich die Objekte speichern möchte? – urig

Verwandte Themen