/// <summary> /// Register an activated (has reconstituted object) surrogate from the data store. /// </summary> internal void RegisterActivatedSurrogate(ICmObjectSurrogate surrogate) { if (surrogate == null) { throw new ArgumentNullException("surrogate"); } if (!surrogate.HasObject) { throw new InvalidOperationException("Has not been reconstituted."); } ICmObject obj = surrogate.Object; var realObj = (ICmObjectOrSurrogate)obj; lock (SyncRoot) { if (!m_IdentityMap.ContainsKey(surrogate.Id)) { throw new InvalidOperationException("Has not been registered."); } // Replace the surrogate with the real object in all the places that we store it so it can be // garbage collected. m_IdentityMap[surrogate.Id] = realObj; var occurrenceSet = m_clsid2Surrogates[m_mdc.GetClassId(surrogate.Classname)]; // These objects are considered equal by the set Equater; but calling Add on a set // does not replace the existing object with an equal one. So we must remove and re-add. occurrenceSet.Remove(surrogate); occurrenceSet.Add(realObj); RegisterObjectHvo(obj); } }
/// <summary> /// Constructor. /// </summary> /// <remarks> /// This Constructor is used for porting from one BEP to another. /// It's faster than getting all the stuff from the xml string. /// </remarks> internal CmObjectSurrogate(LcmCache cache, ICmObjectSurrogate sourceSurrogate) { if (cache == null) { throw new ArgumentNullException("cache"); } if (sourceSurrogate == null) { throw new ArgumentNullException("sourceSurrogate"); } var surr = (CmObjectSurrogate)sourceSurrogate; m_cache = cache; m_object = null; if (surr.RawXmlBytes != null) { RawXmlBytes = surr.RawXmlBytes; } else { Xml = sourceSurrogate.XML; } ICmObjectId objId = surr.Id; m_guid = objId is CmObjectIdWithHvo ? objId : ((IServiceLocatorInternal)cache.ServiceLocator).IdentityMap.CreateObjectIdWithHvo(objId.Guid); SetClassName(surr.m_classname); }
/// <summary> /// Register an inactive (as no object) surrogate from the data store. /// The data needs to be converted, so do the bare minimum registration. /// </summary> internal void RegisterSurrogateForConversion(ICmObjectSurrogate surrogate) { if (surrogate == null) { throw new ArgumentNullException("surrogate"); } if (surrogate.HasObject) { throw new InvalidOperationException("Has already been reconstituted."); } m_IdentityMap[surrogate.Id] = surrogate; }
/// <summary> /// Register an inactive (as no object) surrogate from the data store. /// </summary> internal void RegisterInactiveSurrogate(ICmObjectSurrogate surrogate) { if (surrogate == null) { throw new ArgumentNullException("surrogate"); } if (surrogate.HasObject) { throw new InvalidOperationException("Has already been reconstituted."); } RegisterSurrogate(surrogate); }
private void RegisterSurrogate(ICmObjectSurrogate surrogate) { m_IdentityMap[surrogate.Id] = surrogate; m_clsid2Surrogates[m_mdc.GetClassId(surrogate.Classname)].Add(surrogate); }
/// <summary> /// Gets all unseen foreign changes from the commit log. The metadata should be saved after calling this method, /// because inactive records might have been purged. /// </summary> private bool GetUnseenForeignChanges(CommitLogMetadata metadata, out List <ICmObjectSurrogate> foreignNewbies, out List <ICmObjectSurrogate> foreignDirtballs, out List <ICmObjectId> foreignGoners) { foreignNewbies = new List <ICmObjectSurrogate>(); foreignDirtballs = new List <ICmObjectSurrogate>(); foreignGoners = new List <ICmObjectId>(); int minPeerGeneration = metadata.Peers.Select(p => p.Key == m_peerID ? metadata.CurrentGeneration : p.Value.Generation).Min(); var unseenCommitRecs = new List <CommitLogRecord>(); int bytesRemaining = metadata.LogLength; // read all records up to the end of the file or the end of the log, whichever comes first int length = Math.Min(metadata.LogLength, m_settings.SharedXMLBackendCommitLogSize - metadata.LogOffset - metadata.Padding); bytesRemaining -= ReadUnseenCommitRecords(metadata, minPeerGeneration, metadata.LogOffset, length, unseenCommitRecs); // if there are bytes remaining, it means that we hit the end of the file, so we need to wrap around to the beginning if (bytesRemaining > 0) { bytesRemaining -= ReadUnseenCommitRecords(metadata, minPeerGeneration, 0, bytesRemaining, unseenCommitRecs); } Debug.Assert(bytesRemaining == 0); if (unseenCommitRecs.Count == 0) { return(false); } // check if there was enough room in the commit log for the last peer to write its commit // if it was not able, then we cannot continue, because we will be out-of-sync if (unseenCommitRecs[unseenCommitRecs.Count - 1].WriteGeneration < metadata.CurrentGeneration) { throw new InvalidOperationException("The most recent unseen commit could not be found."); } var idFactory = m_cache.ServiceLocator.GetInstance <ICmObjectIdFactory>(); var newbies = new Dictionary <Guid, ICmObjectSurrogate>(); var dirtballs = new Dictionary <Guid, ICmObjectSurrogate>(); var goners = new HashSet <Guid>(); var surrogateFactory = m_cache.ServiceLocator.GetInstance <ICmObjectSurrogateFactory>(); foreach (CommitLogRecord commitRec in unseenCommitRecs) { if (commitRec.ObjectsDeleted != null) { foreach (Guid goner in commitRec.ObjectsDeleted) { // If it was created by a previous foreign change we haven't seen, we can just forget it. if (newbies.Remove(goner)) { continue; } // If it was modified by a previous foreign change we haven't seen, we can forget the modification. // (but we still need to know it's gone). dirtballs.Remove(goner); goners.Add(goner); } } if (commitRec.ObjectsUpdated != null) { foreach (byte[] dirtballXml in commitRec.ObjectsUpdated) { ICmObjectSurrogate dirtballSurrogate = surrogateFactory.Create(dirtballXml); // This shouldn't be necessary; if a previous foreign transaction deleted it, it // should not show up as a dirtball in a later transaction until it has shown up as a newby. // goners.Remove(dirtball); // If this was previously known as a newby or modified, then to us it still is. if (newbies.ContainsKey(dirtballSurrogate.Guid) || dirtballs.ContainsKey(dirtballSurrogate.Guid)) { continue; } dirtballs[dirtballSurrogate.Guid] = dirtballSurrogate; } } if (commitRec.ObjectsAdded != null) { foreach (byte[] newbyXml in commitRec.ObjectsAdded) { ICmObjectSurrogate newObj = surrogateFactory.Create(newbyXml); if (goners.Remove(newObj.Guid)) { // an object which an earlier transaction deleted is being re-created. // This means that to us, it is a dirtball. dirtballs[newObj.Guid] = newObj; continue; } // It shouldn't be in dirtballs; can't be new in one transaction without having been deleted previously. // So it really is new. newbies[newObj.Guid] = newObj; } } foreignNewbies.AddRange(newbies.Values); foreignDirtballs.AddRange(dirtballs.Values); foreignGoners.AddRange(from guid in goners select idFactory.FromGuid(guid)); } return(true); }
/// <summary> /// Constructor. /// </summary> /// <remarks> /// This Constructor is used for porting from one BEP to another. /// It's faster than getting all the stuff from the xml string. /// </remarks> internal CmObjectSurrogate(FdoCache cache, ICmObjectSurrogate sourceSurrogate) { if (cache == null) throw new ArgumentNullException("cache"); if (sourceSurrogate == null) throw new ArgumentNullException("sourceSurrogate"); var surr = (CmObjectSurrogate) sourceSurrogate; m_cache = cache; m_object = null; if (surr.RawXmlBytes != null) RawXmlBytes = surr.RawXmlBytes; else Xml = sourceSurrogate.XML; ICmObjectId objId = surr.Id; m_guid = objId is CmObjectIdWithHvo ? objId : ((IServiceLocatorInternal)cache.ServiceLocator).IdentityMap.CreateObjectIdWithHvo(objId.Guid); SetClassName(surr.m_classname); }