public override bool Commit(HashSet <ICmObjectOrSurrogate> newbies, HashSet <ICmObjectOrSurrogate> dirtballs, HashSet <ICmObjectId> goners)
        {
            using (m_commitLogMutex.Lock())
            {
                CommitLogMetadata metadata;
                using (MemoryMappedViewStream stream = m_commitLogMetadata.CreateViewStream())
                {
                    metadata = GetMetadata(stream);
                }

                List <ICmObjectSurrogate> foreignNewbies;
                List <ICmObjectSurrogate> foreignDirtballs;
                List <ICmObjectId>        foreignGoners;
                if (GetUnseenForeignChanges(metadata, out foreignNewbies, out foreignDirtballs, out foreignGoners))
                {
                    // we have now seen every commit generation
                    metadata.Peers[m_peerID].Generation = metadata.CurrentGeneration;

                    IUnitOfWorkService uowService = ((IServiceLocatorInternal)m_cache.ServiceLocator).UnitOfWorkService;
                    IReconcileChanges  reconciler = uowService.CreateReconciler(foreignNewbies, foreignDirtballs, foreignGoners);
                    if (reconciler.OkToReconcileChanges())
                    {
                        reconciler.ReconcileForeignChanges();
                        if (metadata.Master == m_peerID)
                        {
                            var newObjects     = new HashSet <ICmObjectOrSurrogate>(foreignNewbies);
                            var editedObjects  = new HashSet <ICmObjectOrSurrogate>(foreignDirtballs);
                            var removedObjects = new HashSet <ICmObjectId>(foreignGoners);

                            IEnumerable <CustomFieldInfo> fields;
                            if (HaveAnythingToCommit(newObjects, editedObjects, removedObjects, out fields) && (StartupVersionNumber == ModelVersion))
                            {
                                PerformCommit(newObjects, editedObjects, removedObjects, fields);
                            }
                        }
                    }
                    else
                    {
                        uowService.ConflictingChanges(reconciler);
                        SaveMetadata(metadata);
                        return(true);
                    }
                }

                CheckExitedPeerProcesses(metadata);
                if (metadata.Master == Guid.Empty)
                {
                    // Check if the former master left the commit log and XML file in a consistent state. If not, we can't continue.
                    if (metadata.CurrentGeneration != metadata.FileGeneration)
                    {
                        throw new InvalidOperationException("The commit log and XML file are in an inconsistent state.");
                    }
                    base.LockProject();
                    metadata.Master = m_peerID;
                }

                IEnumerable <CustomFieldInfo> cfiList;
                if (!HaveAnythingToCommit(newbies, dirtballs, goners, out cfiList) && (StartupVersionNumber == ModelVersion))
                {
                    SaveMetadata(metadata);
                    return(true);
                }

                var commitRec = new CommitLogRecord
                {
                    Source          = m_peerID,
                    WriteGeneration = metadata.CurrentGeneration + 1,
                    ObjectsDeleted  = goners.Select(g => g.Guid).ToList(),
                    ObjectsAdded    = newbies.Select(n => n.XMLBytes).ToList(),
                    ObjectsUpdated  = dirtballs.Select(d => d.XMLBytes).ToList()
                };

                using (var buffer = new MemoryStream())
                {
                    Serializer.SerializeWithLengthPrefix(buffer, commitRec, PrefixStyle.Base128, 1);
                    if (metadata.LogLength + buffer.Length > m_settings.SharedXMLBackendCommitLogSize)
                    {
                        // if this peer is the master, then just skip this commit
                        // other peers will not be able to continue when it cannot find the missing commit, but
                        // the master peer can keep going
                        if (metadata.Master != m_peerID)
                        {
                            throw new InvalidOperationException("The current commit cannot be written to the commit log, because it is full.");
                        }
                    }
                    else
                    {
                        byte[] bytes           = buffer.GetBuffer();
                        int    commitRecOffset = (metadata.LogOffset + metadata.LogLength) % m_settings.SharedXMLBackendCommitLogSize;
                        // check if the record can fit at the end of the commit log. If not, we wrap around to the beginning.
                        if (commitRecOffset + buffer.Length > m_settings.SharedXMLBackendCommitLogSize)
                        {
                            if (metadata.LogLength == 0)
                            {
                                metadata.LogOffset = 0;
                            }
                            else
                            {
                                metadata.Padding = m_settings.SharedXMLBackendCommitLogSize - commitRecOffset;
                            }
                            metadata.LogLength += metadata.Padding;
                            commitRecOffset     = 0;
                        }
                        using (MemoryMappedViewStream stream = m_commitLog.CreateViewStream(commitRecOffset, buffer.Length))
                        {
                            stream.Write(bytes, 0, (int)buffer.Length);
                            metadata.LogLength += (int)buffer.Length;
                        }
                    }
                }

                if (metadata.Master == m_peerID)
                {
                    PerformCommit(newbies, dirtballs, goners, cfiList);
                }

                metadata.CurrentGeneration++;
                // we've seen our own change
                metadata.Peers[m_peerID].Generation = metadata.CurrentGeneration;

                SaveMetadata(metadata);
                return(true);
            }
        }
		public override bool Commit(HashSet<ICmObjectOrSurrogate> newbies, HashSet<ICmObjectOrSurrogate> dirtballs, HashSet<ICmObjectId> goners)
		{
			using (m_commitLogMutex.Lock())
			{
				CommitLogMetadata metadata;
				using (MemoryMappedViewStream stream = m_commitLogMetadata.CreateViewStream())
				{
					metadata = GetMetadata(stream);
				}

				List<ICmObjectSurrogate> foreignNewbies;
				List<ICmObjectSurrogate> foreignDirtballs;
				List<ICmObjectId> foreignGoners;
				if (GetUnseenForeignChanges(metadata, out foreignNewbies, out foreignDirtballs, out foreignGoners))
				{
					// we have now seen every commit generation
					metadata.Peers[m_peerID].Generation = metadata.CurrentGeneration;

					IUnitOfWorkService uowService = ((IServiceLocatorInternal) m_cache.ServiceLocator).UnitOfWorkService;
					IReconcileChanges reconciler = uowService.CreateReconciler(foreignNewbies, foreignDirtballs, foreignGoners);
					if (reconciler.OkToReconcileChanges())
					{
						reconciler.ReconcileForeignChanges();
						if (metadata.Master == m_peerID)
						{
							var newObjects = new HashSet<ICmObjectOrSurrogate>(foreignNewbies);
							var editedObjects = new HashSet<ICmObjectOrSurrogate>(foreignDirtballs);
							var removedObjects = new HashSet<ICmObjectId>(foreignGoners);

							IEnumerable<CustomFieldInfo> fields;
							if (HaveAnythingToCommit(newObjects, editedObjects, removedObjects, out fields) && (StartupVersionNumber == ModelVersion))
								PerformCommit(newObjects, editedObjects, removedObjects, fields);
						}
					}
					else
					{
						uowService.ConflictingChanges(reconciler);
						SaveMetadata(metadata);
						return true;
					}
				}

				CheckExitedPeerProcesses(metadata);
				if (metadata.Master == Guid.Empty)
				{
					// Check if the former master left the commit log and XML file in a consistent state. If not, we can't continue.
					if (metadata.CurrentGeneration != metadata.FileGeneration)
						throw new InvalidOperationException("The commit log and XML file are in an inconsistent state.");
					base.LockProject();
					metadata.Master = m_peerID;
				}

				IEnumerable<CustomFieldInfo> cfiList;
				if (!HaveAnythingToCommit(newbies, dirtballs, goners, out cfiList) && (StartupVersionNumber == ModelVersion))
				{
					SaveMetadata(metadata);
					return true;
				}

				var commitRec = new CommitLogRecord
					{
						Source = m_peerID,
						WriteGeneration = metadata.CurrentGeneration + 1,
						ObjectsDeleted = goners.Select(g => g.Guid).ToList(),
						ObjectsAdded = newbies.Select(n => n.XMLBytes).ToList(),
						ObjectsUpdated = dirtballs.Select(d => d.XMLBytes).ToList()
					};

				using (var buffer = new MemoryStream())
				{
					Serializer.SerializeWithLengthPrefix(buffer, commitRec, PrefixStyle.Base128, 1);
					if (metadata.LogLength + buffer.Length > m_settings.SharedXMLBackendCommitLogSize)
					{
						// if this peer is the master, then just skip this commit
						// other peers will not be able to continue when it cannot find the missing commit, but
						// the master peer can keep going
						if (metadata.Master != m_peerID)
							throw new InvalidOperationException("The current commit cannot be written to the commit log, because it is full.");
					}
					else
					{
						byte[] bytes = buffer.GetBuffer();
						int commitRecOffset = (metadata.LogOffset + metadata.LogLength) % m_settings.SharedXMLBackendCommitLogSize;
						// check if the record can fit at the end of the commit log. If not, we wrap around to the beginning.
						if (commitRecOffset + buffer.Length > m_settings.SharedXMLBackendCommitLogSize)
						{
							if (metadata.LogLength == 0)
								metadata.LogOffset = 0;
							else
								metadata.Padding = m_settings.SharedXMLBackendCommitLogSize - commitRecOffset;
							metadata.LogLength += metadata.Padding;
							commitRecOffset = 0;
						}
						using (MemoryMappedViewStream stream = m_commitLog.CreateViewStream(commitRecOffset, buffer.Length))
						{
							stream.Write(bytes, 0, (int) buffer.Length);
							metadata.LogLength += (int) buffer.Length;
						}
					}
				}

				if (metadata.Master == m_peerID)
					PerformCommit(newbies, dirtballs, goners, cfiList);

				metadata.CurrentGeneration++;
				// we've seen our own change
				metadata.Peers[m_peerID].Generation = metadata.CurrentGeneration;

				SaveMetadata(metadata);
				return true;
			}
		}