/// <summary>
        /// Apply changes sent by a client to the server.
        /// </summary>
        /// <param name="serverBlob">Blob sent in the incoming request</param>
        /// <param name="entities">Changes from the client</param>
        /// <returns>Response containing the new knowledge and conflict/error information.</returns>
        public ApplyChangesResponse ApplyChanges(byte[] serverBlob, List<IOfflineEntity> entities)
        {
            WebUtil.CheckArgumentNull(serverBlob, "serverBlob");
            WebUtil.CheckArgumentNull(entities, "entities");
            
            if (0 == serverBlob.Length)
            {
                throw new InvalidOperationException("serverBlob is empty");
            }

            var syncBlob = new SyncBlob();

            SyncBlob incomingBlob = SyncBlob.DeSerialize(serverBlob);

            PopulateClientScopeNameAndSyncId(incomingBlob);
            
            // Set the scope name in the response blob.
            syncBlob.ClientScopeName = incomingBlob.ClientScopeName;
            
            // If the requested scope does not exists, then throw an error since we 
            // don't initialize scopes on upload requests.
            if (!CheckIfScopeExists())
            {
                throw SyncServiceException.CreateResourceNotFound("Scope does not exist");
            }

            byte[] clientKnowledgeBlob = incomingBlob.ClientKnowledge;

            // Initialize a SqlSyncProvider object.
            _sqlSyncProvider = CreateSqlSyncProviderInstance(_clientScopeName, _serverConnectionString, _configuration.SyncObjectSchema);

            var response = new ApplyChangesResponse();

            // Deserialize the knowledge or create new empty knowledge.
            SyncKnowledge clientKnowledge = GetSyncKnowledgeFromBlob(clientKnowledgeBlob);

            // If there are no entities to upload, then return the client knowledge as is.
            if (entities.Count == 0)
            {
                response.Conflicts = new List<SyncConflict>();
                response.Errors = new List<SyncError>();
                
                syncBlob.ClientKnowledge = clientKnowledge.Serialize();

                response.ServerBlob = syncBlob.Serialize();

                return response;
            }

            // Client never has any forgotten knowledge. So create a new one.
            var forgottenKnowledge = new ForgottenKnowledge(_sqlSyncProvider.IdFormats, clientKnowledge);

            // Convert the entities to dataset using the custom converter.
            DataSet changesDS = _converter.ConvertEntitiesToDataSet(entities);

            var stats = new SyncSessionStatistics();
            var sessionContext = new SyncSessionContext(_sqlSyncProvider.IdFormats, new SyncCallbacks());

            _sqlSyncProvider.BeginSession(SyncProviderPosition.Remote, sessionContext);

            ulong tickCount = 0;
            SyncKnowledge updatedClientKnowldege;

            try
            {
                uint batchSize;
                SyncKnowledge serverKnowledge;

                // This gives us the server knowledge.
                _sqlSyncProvider.GetSyncBatchParameters(out batchSize, out serverKnowledge);

                var changeBatch = new ChangeBatch(_sqlSyncProvider.IdFormats, clientKnowledge, forgottenKnowledge);
                changeBatch.SetLastBatch();

                //Note: There is a possiblity of (-ve) item exceptions , between two uploads from the 
                // same client (for example: in case of RI failures). This would result in an incorrect value if the function
                // FindMinTickCountForReplica is used to get the last tickcount. So, we need to ignore the -ve item exceptions 
                // when finding the tickcount for the client replica from the server knowledge.

                /* Logic:
                 * SyncKnowledge.GetKnowledgeForItemId could be used for itemid Zero and then we can find the mintickcount for client replica id.
                 * This does not however seem to work, so we use the KnowledgeInspector and enumerate over each ClockVector
                 * and find the client clockvector and get its tickcount.
                 * 
                 * Assumption: The above approach assumes that we don't have any positive exceptions in the knowledge.
                 */
                try
                {
                    // Check if the client replica key exists.
                    uint clientReplicaKey = serverKnowledge.ReplicaKeyMap.LookupReplicaKey(_clientSyncId);

                    var ki = new KnowledgeInspector(1, serverKnowledge);
                    var clockVector = (ClockVector)ki.ScopeClockVector;
                    int noOfReplicaKeys = clockVector.Count;

                    for (int i = noOfReplicaKeys - 1; i >= 0; i--)
                    {
                        if (clockVector[i].ReplicaKey == clientReplicaKey)
                        {
                            tickCount = clockVector[i].TickCount;
                            break;
                        }
                    }
                }
                catch (ReplicaNotFoundException exception)
                {
                    SyncTracer.Info("ReplicaNotFoundException. NEW CLIENT. Exception details: {0}",
                                    WebUtil.GetExceptionMessage(exception));
                    // If the knowedge does not contain the client replica (first apply), initialize tickcount to zero.
                    tickCount = 0;
                }

                // Increment the tickcount
                tickCount++;

                // update the made with knowledge to include the new tickcount.
                updatedClientKnowldege = new SyncKnowledge(_sqlSyncProvider.IdFormats, _clientSyncId, tickCount);
                updatedClientKnowldege.Combine(clientKnowledge);

                // The incoming data does not have metadata for each item, so we need to create it at this point.
                AddSyncColumnsToDataSet(changesDS, tickCount);

                // Make DbSyncContext
                var dbSyncContext = new DbSyncContext
                {
                    IsDataBatched = false,
                    IsLastBatch = true,
                    DataSet = changesDS,
                    MadeWithKnowledge = updatedClientKnowldege,
                    MadeWithForgottenKnowledge = forgottenKnowledge,
                    ScopeProgress = new DbSyncScopeProgress()
                };

                _conflicts = new List<SyncConflict>();
                _syncErrors = new List<SyncError>();

                // Subscribe to the ApplyChangeFailed event to handle conflicts.
                _sqlSyncProvider.ApplyChangeFailed += SqlSyncProviderApplyChangeFailed;

                // Subscribe to the ChangesApplied event to read the server tickcount incase there are any conflicts.
                _sqlSyncProvider.ChangesApplied += SqlSyncProviderChangesApplied;

                //NOTE: The ConflictResolutionPolicy pass into the method is IGNORED.
                // Conflicts can be logged by subscribing to the failed events
                _sqlSyncProvider.ProcessChangeBatch(Microsoft.Synchronization.ConflictResolutionPolicy.DestinationWins,
                                                   changeBatch,
                                                   dbSyncContext, new SyncCallbacks(), stats);

                if (0 != _conflicts.Count)
                {
                    _sqlSyncProvider.GetSyncBatchParameters(out batchSize, out serverKnowledge);

                    // The way the current P2P provider works, versions are bumped up when conflicts are resolved on the server.
                    // This would result in us sending the changes to the client on the next download request. We want
                    // to not enumerate that change again on the next request from the same client. 
                    // The solution is to get the server knowledge after all changes are applied and then
                    // project the knowledge of each conflictign item and add it as a positive exception to the updated client knowledge.

                    AddConflictItemsKnowledgeToClientKnowledge(updatedClientKnowldege, serverKnowledge);
                }
            }
            finally
            {
                _sqlSyncProvider.EndSession(sessionContext);
            }

            // Don't send any updates to the server knowledge since the client has not got any updates yet.
            // This updated knowledge will only include an update to the client tickcount.
            // The client would obtain the server knowledge when it does a get changes.
            // If we include the serverknowlege, the client would never get any items that are
            // between the current server knowledge and the client known server knowledge.

            syncBlob.ClientKnowledge = updatedClientKnowldege.Serialize();
            response.ServerBlob = syncBlob.Serialize();

            response.Conflicts = _conflicts;
            response.Errors = _syncErrors;

            return response;
        }
        //Simply ask the metadata store to compute my change batch for me, providing the batch size and the knowledge of the other endpoint!
        //The engine is asking for the list of changes that the destination provider does not know about.
        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
        {
            ChangeBatch batch = _metadata.GetChangeBatch(batchSize, destinationKnowledge);

            changeDataRetriever = this; //this is where the transfer mechanism/protocol would go. For an in memory provider, this is sufficient
            return(batch);
        }
Exemplo n.º 3
0
        internal static void SetLocalTickCountRanges(SyncKnowledge knowledge, ulong newTick)
        {
            SyncKnowledge knowledge1 = knowledge.Clone();

            knowledge.SetLocalTickCount(newTick);
            knowledge.Combine(knowledge1);
        }
 public ChangeBatch GetChanges(
     uint batchSize,
     SyncKnowledge destinationKnowledge,
     out object changeData)
 {
     return(peerProvider.GetChangeBatch(batchSize, destinationKnowledge, out changeData));
 }
 public override FullEnumerationChangeBatch GetFullEnumerationChangeBatch(uint batchSize, SyncId lowerEnumerationBound,
                                                                          SyncKnowledge knowledgeForDataRetrieval, out object changeDataRetriever)
 {
     //Do nothing.
     //
     throw new NotImplementedException();
 }
Exemplo n.º 6
0
        /// <summary>
        /// Возвращает пакет изменений, содержащий метаданные элементов, которые отсутствовали в указанном наборе знаний от поставщика назначения
        /// </summary>
        /// <param name="batchSize">Size of the batch.</param>
        /// <param name="destinationKnowledge">The destination knowledge.</param>
        /// <returns></returns>
        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge)
        {
            ChangeBatch retVal    = null;
            ulong       tickCount = GetNextTickCount();


            List <ItemChange> changes = DetectChanges(destinationKnowledge, batchSize);

            retVal = new ChangeBatch(IdFormats, destinationKnowledge, Replica.ForgottenKnowledge);

            // Add the changes to the ChangeBatch with our made with knowledge
            // (Made width knowledge is the knowledge the other side will "learn" if they apply these
            // changes successfully)
            retVal.BeginUnorderedGroup();
            retVal.AddChanges(changes);
            // If last change batch, mark accordingly
            // (We always enumerate full batches, so if our batch is less than the batch size we
            // must be at the last batch. The second condition is spurious.)
            bool isLastBatch = false;

            if ((changes.Count < batchSize) || (changes.Count == 0))
            {
                retVal.SetLastBatch();
                isLastBatch = true;
            }

            retVal.EndUnorderedGroup(Replica.CurrentKnowledge, isLastBatch);

            return(retVal);
        }
Exemplo n.º 7
0
        public void Load()
        {
            string syncFile = Path.Combine(folderPath, SyncDetails.METADATA_STORE_FILENAME);

            if (File.Exists(syncFile))
            {
                using (FileStream stream = new FileStream(syncFile, FileMode.Open)) {
                    BinaryFormatter bf = new BinaryFormatter();
                    ReplicaId = (SyncId)bf.Deserialize(stream);
                    tickCount = (ulong)bf.Deserialize(stream);
                    // Load Knowledge File
                    SyncKnowledge = (SyncKnowledge)bf.Deserialize(stream);
                    if (SyncKnowledge.ReplicaId != ReplicaId)
                    {
                        throw new Exception("Replica id of loaded knowledge doesn't match replica id provided in constructor.");
                    }
                    ForgottenKnowledge = (ForgottenKnowledge)bf.Deserialize(stream);
                    if (ForgottenKnowledge.ReplicaId != ReplicaId)
                    {
                        throw new Exception("Replica id of loaded forgotten knowledge doesn't match replica id provided in constructor.");
                    }
                    // Load the meta data store
                    metadataStore.Load(stream);
                }
            }
            else
            {
                ReplicaId          = new SyncId(Guid.NewGuid());
                SyncKnowledge      = new SyncKnowledge(IdFormats, ReplicaId, tickCount);
                ForgottenKnowledge = new ForgottenKnowledge(IdFormats, SyncKnowledge);
            }
        }
Exemplo n.º 8
0
        public List <ItemChange> GetChanges(ChangeBatch sourceChanges)
        {
            // Increment the tick count
            GetNextTickCount();

            // Increase local knowledge tick count.
            SyncKnowledge.SetLocalTickCount(tickCount);

            // Create a collection to hold the changes we'll put into our batch
            List <ItemChange> changes = new List <ItemChange>();

            foreach (ItemChange ic in sourceChanges)
            {
                ItemMetadata item;
                ItemChange   change;
                // Iterate through each item to get the corresponding version in the local store
                if (metadataStore.TryGetItem(ic.ItemId, out item))
                {
                    // Found the corresponding item in the local metadata
                    // Get the local creation version and change (update) version from the metadata
                    change = new ItemChange(IdFormats, ReplicaId, item.ItemId, item.IsTombstone ? ChangeKind.Deleted: ChangeKind.Update, item.CreationVersion, item.ChangeVersion);
                }
                else
                {
                    // Remote item has no local counterpart
                    // This item is unknown to us
                    change = new ItemChange(IdFormats, ReplicaId, ic.ItemId, ChangeKind.UnknownItem, SyncVersion.UnknownVersion, SyncVersion.UnknownVersion);
                }

                // Add our change to the change list
                changes.Add(change);
            }

            return(changes);
        }
Exemplo n.º 9
0
        //Simply store the knowlege given to us
        public void StoreKnowledgeForScope(SyncKnowledge knowledge, ForgottenKnowledge forgottenKnowledge)
        {
            _metadata.SetKnowledge(knowledge);
            _metadata.SetForgottenKnowledge(forgottenKnowledge);

            _metadata.SaveReplicaMetadata();
        }
Exemplo n.º 10
0
        public SyncKnowledge ProjectOnKnowledge(SyncKnowledge sourceKnowledge)
        {
            SyncKnowledge cumulativeKnowledge = null;

            foreach (BatchRange curRange in _ranges)
            {
                if (!curRange.RangeIsUsable)
                {
                    // break on last range if it is not usable
                    Debug.Assert(curRange == Last);
                    break;
                }
                SyncKnowledge knowledgeForUnion =
                    sourceKnowledge.GetKnowledgeForRange(curRange.Start, curRange.End);

                if (cumulativeKnowledge == null)
                {
                    cumulativeKnowledge = knowledgeForUnion;
                }
                else
                {
                    cumulativeKnowledge.Combine(knowledgeForUnion);
                }
            }
            return(cumulativeKnowledge);
        }
Exemplo n.º 11
0
        public byte[] GetChangeBatch(uint batchSize, byte[] rawDestinationKnowledge,
                                     out byte[] changeDataRetriever)
        {
            GenericRemoteSyncProvider <EntityObjectHierarchy> provider = GetSessionProvider();

            byte[] retVal = null;
            try
            {
                SyncKnowledge             destinationKnowledge = SyncKnowledge.Deserialize(provider.IdFormats, rawDestinationKnowledge);
                object                    dataRetriever;
                ChangeBatch               changeBatch = provider.GetChangeBatch(batchSize, destinationKnowledge, out dataRetriever);
                CachedChangeDataRetriever cachedChangeDataRetriever =
                    new CachedChangeDataRetriever(dataRetriever as IChangeDataRetriever, changeBatch);
                string debugCachedRetr = SerializerHelper.XmlSerialize(cachedChangeDataRetriever);
                changeDataRetriever = SerializerHelper.BinarySerialize(cachedChangeDataRetriever);
                retVal = changeBatch.Serialize();
            }
            catch (SyncException e)
            {
                throw SoapErrorCreator.RaiseException(HttpContext.Current.Request.Url.ToString(),
                                                      new SyncronizationServiceError(SyncronizationServiceError.eServiceErrorType.SyncFramework, e),
                                                      true);
            }
            catch (Exception e)
            {
                throw SoapErrorCreator.RaiseException(HttpContext.Current.Request.Url.ToString(),
                                                      new SyncronizationServiceError(SyncronizationServiceError.eServiceErrorType.SyncProvider, e),
                                                      true);
            }
            return(retVal);
        }
Exemplo n.º 12
0
        public override void GetSyncBatchParameters(out uint batchSize, out SyncKnowledge knowledge)
        {
            SyncBatchParameters wrapper = proxy.GetKnowledge();

            batchSize = wrapper.BatchSize;
            knowledge = wrapper.DestinationKnowledge;
        }
Exemplo n.º 13
0
        public override void GetSyncBatchParameters(out uint batchSize, out SyncKnowledge knowledge)
        {
            SyncBatchParameters batchParams = Proxy.GetKnowledge();

            batchSize = batchParams.BatchSize;
            knowledge = batchParams.DestinationKnowledge;
        }
Exemplo n.º 14
0
        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
        {
            ChangeBatch batch = _metadataStore.Metadata.GetChangeBatch(batchSize, destinationKnowledge);

            changeDataRetriever = _changeApplier;
            return(batch);
        }
Exemplo n.º 15
0
        public ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out ForgottenKnowledge forgottenKnowledge, out object changeDataRetriever)
        {
            // Increment the tick count
            GetNextTickCount();

            // Get local changes
            List <ItemChange> changes = DetectChanges(destinationKnowledge, batchSize);

            // Update the knowledge with an updated local tick count
            SyncKnowledge.SetLocalTickCount(tickCount);

            // Construct the ChangeBatch and return it
            ChangeBatch changeBatch = new ChangeBatch(IdFormats, destinationKnowledge, ForgottenKnowledge);

            changeBatch.BeginUnorderedGroup();
            changeBatch.AddChanges(changes);
            if (changes.Count < batchSize || changes.Count == 0)
            {
                changeBatch.SetLastBatch();
            }
            changeBatch.EndUnorderedGroup(SyncKnowledge, changeBatch.IsLastBatch);

            // Return the forgotten knowledge
            forgottenKnowledge = ForgottenKnowledge;

            changeDataRetriever = this;

            return(changeBatch);
        }
Exemplo n.º 16
0
        /// <summary>
        /// Detects changes not known to the destination and returns a change batch
        /// </summary>
        /// <param name="destinationKnowledge">Requester Knowledge</param>
        /// <param name="batchSize">Maximum number of changes to return</param>
        /// <returns>List of changes</returns>
        private List <ItemChange> DetectChanges(SyncKnowledge destinationKnowledge, SyncId lowerEnumerationBound, uint batchSize)
        {
            List <ItemChange> retVal = new List <ItemChange>();

            if (destinationKnowledge == null)
            {
                throw new ArgumentNullException("destinationKnowledge");
            }
            if (batchSize < 0)
            {
                throw new ArgumentOutOfRangeException("batchSize");
            }

            ulong currentLocalTickCount = Replica.TickCount;

            // Update local knowledge with the current local tick count
            Replica.CurrentKnowledge.SetLocalTickCount(currentLocalTickCount);

            // Map the destination knowledge
            // This maps the knowledge from the remote replica key map (where the destination is replicaKey 0)
            // to the local replica key map (where the source is replicaKey)
            //
            // We do this because our metadata is relative to the local store (and local key map)
            // (This is typical of most sync providers)
            SyncKnowledge mappedKnowledge = Replica.CurrentKnowledge.MapRemoteKnowledgeToLocal(destinationKnowledge);

            foreach (ItemMetadata item in Replica.EntityMetadataItems.Where(x => x.GlobalId.CompareTo(lowerEnumerationBound) >= 0))
            {
                // Check if the current version of the item is known to the destination
                // We simply check if the update version is contained in his knowledge

                // If the metadata is for a tombstone, the change is a delete

                if (!mappedKnowledge.Contains(Replica.ReplicaId, item.GlobalId, item.ChangeVersion))
                {
                    ItemChange itemChange = new ItemChange(IdFormats, Replica.ReplicaId, item.GlobalId,
                                                           item.IsDeleted ? ChangeKind.Deleted : ChangeKind.Update,
                                                           item.CreationVersion, item.ChangeVersion);

                    // Change isn't known to the remote store, so add it to the batch

                    retVal.Add(itemChange);
                }

                // If the batch is full, break
                //
                // N.B. Rest of changes will be detected in next batch. Current batch will not be
                // reenumerated (except in case destination doesn't successfully apply them) as
                // when destination applies the changes in this batch, they will add them to their
                // knowledge.

                if (retVal.Count == batchSize)
                {
                    break;
                }
            }

            return(retVal);
        }
 public void GetSyncBatchParameters(
     out uint batchSize,
     out SyncKnowledge knowledge)
 {
     base.Channel.GetSyncBatchParameters(
         out batchSize,
         out knowledge);
 }
Exemplo n.º 18
0
 public void GetSyncBatchParameters(
     out uint batchSize,
     out SyncKnowledge knowledge)
 {
     provider.GetSyncBatchParameters(
         out batchSize,
         out knowledge);
 }
Exemplo n.º 19
0
        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destKnowledge, out object changeDataRetriever)
        {
            FileChangesParameters changesParams = Proxy.GetChanges(batchSize, destKnowledge);

            changeDataRetriever = changesParams.DataRetriever;

            return(changesParams.ChangeBatch);
        }
Exemplo n.º 20
0
 public override void GetSyncBatchParameters(
     out uint batchSize,
     out SyncKnowledge knowledge)
 {
     this.client.GetSyncBatchParameters(
         out batchSize,
         out knowledge);
 }
Exemplo n.º 21
0
        public byte[] GetChanges(uint batchSize, SyncKnowledge destinationKnowledge, LocalSyncDetails syncDetails)
        {
            ChangeBatchTransfer changeBatch = new ChangeBatchTransfer();
            object dataRetriver = new object();
            changeBatch.ChangeBatch = syncDetails.GetChangeBatch(RemoteDirectoryPath, batchSize, destinationKnowledge, out dataRetriver);
            changeBatch.ChangeDataRetriever = dataRetriver;

            return changeBatch.ObjectToByteArray();
        }
Exemplo n.º 22
0
 public override void StoreKnowledgeForScope(SyncKnowledge knowledge, ForgottenKnowledge forgottenKnowledge)
 {
     try {
         Proxy.StoreKnowledgeForScope(Path, knowledge, forgottenKnowledge, _filters);
     }
     catch (Exception exc) {
         throw exc;
     }
 }
Exemplo n.º 23
0
        public override ChangeBatch GetChangeBatch(uint batchSize,
                                                   SyncKnowledge destinationKnowledge, out object changeDataRetriever)
        {
            var changesWrapper = _proxy.GetChanges(batchSize,
                                                   destinationKnowledge);

            //Retrieve the ChangeDataRetriever and the ChangeBatch
            changeDataRetriever = changesWrapper.DataRetriever;

            var context = changeDataRetriever as DbSyncContext;

            //Check to see if the data is batched.
            if (context != null && context.IsDataBatched)
            {
                if (localBatchingDirectory == null)
                {
                    //Retrieve the remote peer id from the
                    //MadeWithKnowledge.ReplicaId. MadeWithKnowledge is the local
                    //knowledge of the peer that is enumerating the changes.
                    var remotePeerId = context.MadeWithKnowledge.ReplicaId.ToString();

                    //Generate a unique Id for the directory.
                    //We use the peer id of the store enumerating the changes so
                    //that the local temp directory is same for a given source
                    //across sync sessions. This enables us to restart a failed sync
                    //by not downloading already received files.
                    var sessionDir =
                        Path.Combine(batchingDirectory, "WebSync_" + remotePeerId);
                    localBatchingDirectory = new DirectoryInfo(sessionDir);
                    //Create the directory if it doesnt exist.
                    if (!localBatchingDirectory.Exists)
                    {
                        localBatchingDirectory.Create();
                    }
                }

                var localFileName = Path.Combine(localBatchingDirectory.FullName,
                                                 context.BatchFileName);
                var localFileInfo = new FileInfo(localFileName);

                //Download the file only if doesnt exist
                if (!localFileInfo.Exists)
                {
                    var remoteFileContents =
                        _proxy.DownloadBatchFile(context.BatchFileName);
                    using (var localFileStream = new FileStream(localFileName,
                                                                FileMode.Create, FileAccess.Write))
                    {
                        localFileStream.Write(remoteFileContents, 0, remoteFileContents.Length);
                    }
                }
                //Set DbSyncContext.Batchfile name to the new local file name
                context.BatchFileName = localFileName;
            }

            return(changesWrapper.ChangeBatch);
        }
 public ChangeBatch GetChangeBatch(
     uint batchSize,
     SyncKnowledge destinationKnowledge,
     out Sync101.CachedChangeDataRetriever changeDataRetriever)
 {
     return(base.Channel.GetChangeBatch(
                batchSize,
                destinationKnowledge,
                out changeDataRetriever));
 }
Exemplo n.º 25
0
        // need the scopeName for error message
        public RowSorter(SyncKnowledge srcKnowledge,
                         string scopeName,
                         long MaximumSortedBatchSizeInKB)
        {
            _scopeName = scopeName;
            _maxSortedBatchSizeInKB = MaximumSortedBatchSizeInKB;
            _srcKnowledge           = srcKnowledge;

            _tablesInApplyOrder = new List <string>();
            _sortedTables       = new Dictionary <string, SortedTable>();
        }
Exemplo n.º 26
0
 public void SaveConstraintConflict(
     ItemChange conflictingChange,
     SyncId conflictingItemId,
     ConstraintConflictReason reason,
     object conflictingChangeData,
     SyncKnowledge conflictingChangeKnowledge,
     bool temporary)
 {
     var i = 1;
     // just to implement the interface
 }
Exemplo n.º 27
0
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out ForgottenKnowledge forgottenKnowledge, out object changeDataRetriever)
        {
            forgottenKnowledge  = null;
            changeDataRetriever = "hello";
            ChangeBatchBuilder cb = new ChangeBatchBuilder(idFormats);
            ItemChange         ic = new ItemChange(idFormats, destinationKnowledge.ReplicaId,
                                                   new SyncId("1"), new SyncVersion(0, 0), new SyncVersion(1, 1));

            cb.AddChanges(new ItemChange [] { ic }, destinationKnowledge, false);
            return(cb.GetChangeBatch());
        }
Exemplo n.º 28
0
        /// <summary>
        /// Detects changes not known to the destination and returns a change batch
        /// </summary>
        /// <param name="destinationKnowledge">Requester Knowledge</param>
        /// <param name="batchSize">Maximum number of changes to return</param>
        /// <returns>List of changes</returns>
        private List <ItemChange> DetectChanges(SyncKnowledge destinationKnowledge, uint batchSize)
        {
            List <ItemChange> changeBatch = new List <ItemChange>();

            if (destinationKnowledge == null)
            {
                throw new ArgumentNullException("destinationKnowledge");
            }
            if (batchSize < 0)
            {
                throw new ArgumentOutOfRangeException("batchSize");
            }

            if (!localChangedDetected)
            {
                FindLocalFileChanges(folderPath);
                localChangedDetected = true;
            }

            // Map the destination knowledge
            // This maps the knowledge from the remote replica key map (where the destination is replicaKey 0)
            // to the local replica key map (where the source is replicaKey)
            //
            // We do this because our metadata is relative to the local store (and local key map)
            // (This is typical of most sync providers)
            SyncKnowledge mappedKnowledge = SyncKnowledge.MapRemoteKnowledgeToLocal(destinationKnowledge);

            foreach (ItemMetadata item in metadataStore)
            {
                // Check if the current version of the item is known to the destination
                // We simply check if the update version is contained in his knowledge

                // If the metadata is for a tombstone, the change is a delete
                if (!mappedKnowledge.Contains(ReplicaId, item.ItemId, item.ChangeVersion))
                {
                    ItemChange itemChange = new ItemChange(IdFormats, ReplicaId, item.ItemId, item.IsTombstone ? ChangeKind.Deleted : ChangeKind.Update, item.CreationVersion, item.ChangeVersion);
                    // Change isn't known to the remote store, so add it to the batch
                    changeBatch.Add(itemChange);
                }

                // If the batch is full, break
                //
                // N.B. Rest of changes will be detected in next batch. Current batch will not be
                // reenumerated (except in case destination doesn't successfully apply them) as
                // when destination applies the changes in this batch, they will add them to their
                // knowledge.
                if (changeBatch.Count == batchSize)
                {
                    break;
                }
            }

            return(changeBatch);
        }
Exemplo n.º 29
0
        public override void GetSyncBatchParameters(out uint batchSize, out SyncKnowledge knowledge)
        {
            batchSize = RequestedBatchSize;
            try {
                SyncKnowledge = Proxy.GetCurrentSyncKnowledge(Path, _filters);
            }
            catch (Exception ex) {
                throw ex;
            }

            knowledge = SyncKnowledge.Clone();
        }
Exemplo n.º 30
0
        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
        {
            var         temp  = _metadata.GetChangeBatch(uint.MaxValue, destinationKnowledge);
            ChangeBatch batch = _metadata.GetChangeBatch(batchSize, destinationKnowledge);

            changeDataRetriever = this; //this is where the transfer mechanism/protocol would go. For an in memory provider, this is sufficient
            var batchCount = (uint)batch.Count();

            batch.BatchWorkEstimate            = batchCount;
            batch.RemainingSessionWorkEstimate = (uint)temp.Count();
            return(batch);
        }
 public FullEnumerationChangeBatch GetFullEnumerationChangeBatch(
     uint batchSize,
     SyncId lowerEnumerationBound,
     SyncKnowledge knowledgeForDataRetrieval,
     out Sync101.CachedChangeDataRetriever changeDataRetriever)
 {
     return(base.Channel.GetFullEnumerationChangeBatch(
                batchSize,
                lowerEnumerationBound,
                knowledgeForDataRetrieval,
                out changeDataRetriever));
 }
Exemplo n.º 32
0
        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
        {
            ChangeBatch batch = _metaData.GetChangeBatch(batchSize, destinationKnowledge);

            changeDataRetriever = this;             //this is where the transfer mechanism/protocol would go. For an in memory provider, this is sufficient

            //Calculate estimate work
            batch.RemainingSessionWorkEstimate = RemainingSessionWorkEstimate;
            batch.BatchWorkEstimate            = batch.IsLastBatch ? (uint)batch.Count() : batchSize;
            RemainingSessionWorkEstimate       = batch.IsLastBatch ? 0 : RemainingSessionWorkEstimate - batchSize;

            return(batch);
        }
Exemplo n.º 33
0
        public static string KToString(SyncKnowledge knowlege)
        {
            String retVal = "";

            System.IO.MemoryStream memStream = new System.IO.MemoryStream();
            System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(memStream, Encoding.UTF8);
            writer.Formatting = System.Xml.Formatting.Indented;
            knowlege.WriteXml(writer);
            writer.Flush();
            memStream.Seek(0, System.IO.SeekOrigin.Begin);
            System.IO.StreamReader reader = new System.IO.StreamReader(memStream);
            retVal = reader.ReadToEnd();

            return retVal;
        }
Exemplo n.º 34
0
        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
        {
            System.Diagnostics.Debug.WriteLine("GetChangeBatch:" + destinationKnowledge.ToString());
            changeDataRetriever = this;

            ChangeBatchTransfer batch = (ChangeBatchTransfer)service.GetChanges(batchSize, destinationKnowledge, sync.Cast<LocalSyncDetails>()).ByteArrayToObject();

            ChangeBatch changeBatch = batch.ChangeBatch;
            changeDataRetriever = batch.ChangeDataRetriever;

            changeDataRetriever = changeDataRetriever.Cast<RemoteSyncDetails>();
            sync = changeDataRetriever.Cast<RemoteSyncDetails>();

            ((RemoteSyncDetails)(changeDataRetriever)).Service = service;
            return changeBatch;
        }
Exemplo n.º 35
0
        public ChangeBatch GetChangeBatch(string path, uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
        {
            folderPath = path;
            GetNextTickCount();

            List<ItemChange> changes = DetectChanges(destinationKnowledge, batchSize);

            myKnowledge.SetLocalTickCount(tickCount);

            ChangeBatch changeBatchBuilder = new ChangeBatch(IdFormats,destinationKnowledge,  myForgottenKnowledge);

            changeBatchBuilder.BeginUnorderedGroup();

            changeBatchBuilder.AddChanges(changes);

            changeBatchBuilder.EndUnorderedGroup(myKnowledge, true);

            if ((changes.Count < batchSize) || (changes.Count == 0))
            {
                changeBatchBuilder.SetLastBatch();
            }

            changeDataRetriever = this;

            return changeBatchBuilder;
        }
Exemplo n.º 36
0
 public void StoreKnowledgeForScope(SyncKnowledge knowledge, ForgottenKnowledge forgottenKnowledge)
 {
     sync.StoreKnowledgeForScope(knowledge, forgottenKnowledge);
     System.Diagnostics.Debug.WriteLine("    ### StoreKnowledgeForScope ###");
 }
Exemplo n.º 37
0
 public void StoreKnowledgeForScope(SyncKnowledge knowledge, ForgottenKnowledge forgotten)
 {
     using (SyncDetails sync = new LocalSyncDetails(RemoteDirectoryPath, false))
     {
         sync.StoreKnowledgeForScope(knowledge, forgotten);
     }
 }
Exemplo n.º 38
0
        //Simply ask the metadata store to compute my change batch for me, providing the batch size and the knowledge of the other endpoint!
        //The engine is asking for the list of changes that the destination provider does not know about.
        public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
        {
            ChangeBatch batch = _metadata.GetChangeBatch(batchSize, destinationKnowledge);
            foreach (ItemChange change in batch)
            {
                Trace.WriteLine(change.ItemId + "" + change.ChangeKind);
            }
            changeDataRetriever = this; //this is where the transfer mechanism/protocol would go. For an in memory provider, this is sufficient
            uint changesCount = 0;
            foreach (ItemChange itemChange in batch)
            {
                changesCount++;
            }
            batch.RemainingSessionWorkEstimate = _syncItemCount;
            batch.BatchWorkEstimate =  batch.IsLastBatch ? changesCount : batchSize;
            _syncItemCount = batch.IsLastBatch ? 0 : _syncItemCount - batchSize;

            return batch;
        }
Exemplo n.º 39
0
 public override FullEnumerationChangeBatch GetFullEnumerationChangeBatch(uint batchSize, SyncId lowerEnumerationBound, SyncKnowledge knowledgeForDataRetrieval, out object changeDataRetriever)
 {
     FullEnumerationChangeBatch batch = _metadataStore.Metadata.GetFullEnumerationChangeBatch(batchSize, lowerEnumerationBound, knowledgeForDataRetrieval);
     changeDataRetriever = _changeApplier;
     return batch;
 }
Exemplo n.º 40
0
        private List<ItemChange> DetectChanges(SyncKnowledge destinationKnowledge, uint batchSize)
        {
            System.Diagnostics.Debug.WriteLine(" Start DetectChanges in:" + folderPath);

            List<ItemChange> changeBatch = new List<ItemChange>();

            if (destinationKnowledge == null)
                throw new ArgumentNullException("destinationKnowledge");

            if (batchSize < 0)
                throw new ArgumentOutOfRangeException("batchSize");

            if (!localChangedDetected)
            {
                FindLocalFileChanges(folderPath);
                localChangedDetected = true;
            }

            SyncKnowledge mappedKnowledge = myKnowledge.MapRemoteKnowledgeToLocal(destinationKnowledge);

            System.Diagnostics.Debug.WriteLine("  Is the current version of the item is known to the destination ?");
            foreach (ItemMetadata item in metadataStore)
            {
                if (!mappedKnowledge.Contains(replicaId, item.ItemId, item.ChangeVersion))// Create
                {
                    System.Diagnostics.Debug.WriteLine("Not Known:" + item.Uri + " IsTombstone:" + item.IsTombstone.ToString());
                    ItemChange itemChange = new ItemChange(IdFormats, replicaId, item.ItemId,
                        (item.IsTombstone) ? ChangeKind.Deleted : ChangeKind.Update,
                        item.CreationVersion, item.ChangeVersion);

                    changeBatch.Add(itemChange);
                }
                else if (item.IsTombstone)//Delete
                {
                    System.Diagnostics.Debug.WriteLine("Item is Known:" + item.Uri + " Its a Tombstone so add it:");

                    ItemChange itemChange = new ItemChange(IdFormats, replicaId, item.ItemId, ChangeKind.Deleted, item.CreationVersion, item.ChangeVersion);
                    changeBatch.Add(itemChange);
                }
                else//Update
                {
                    System.Diagnostics.Debug.WriteLine("mappedKnowledge is know item " + item.Uri + " And was no tombstone");
                    ItemChange itemChange = new ItemChange(IdFormats, replicaId, item.ItemId, ChangeKind.Update,
                        item.CreationVersion, item.ChangeVersion);

                    changeBatch.Add(itemChange);
                }

                if (changeBatch.Count == batchSize)
                    break;
            }
            System.Diagnostics.Debug.WriteLine("        #### End DetectChanges ####");
            return changeBatch;
        }
Exemplo n.º 41
0
        public GetChangesParameters GetChanges(uint batchSize, SyncKnowledge destinationKnowledge)
        {
            GetChangesParameters changesWrapper = new GetChangesParameters();
            changesWrapper.ChangeBatch = this.peerProvider.GetChangeBatch(batchSize, destinationKnowledge, out changesWrapper.DataRetriever);

            DbSyncContext context = changesWrapper.DataRetriever as DbSyncContext;
            //Check to see if data is batched
            if (context != null && context.IsDataBatched)
            {
                string fileName = new FileInfo(context.BatchFileName).Name;
                this.batchIdToFileMapper[fileName] = context.BatchFileName;
                context.BatchFileName = fileName;
            }
            return changesWrapper;
        }
Exemplo n.º 42
0
 public void SaveConflict(ItemChange conflictingChange, object conflictingChangeData, SyncKnowledge conflictingChangeKnowledge)
 {
     //Conflicts are always merged so there is never a conflict to save.  See DestinationCallbacks_ItemConflicting in MyTestProgram 
     //and the SaveChangeAction.UpdateVersionAndMergeData case in SaveChange below to see how conflicts are merged.
     throw new NotImplementedException();
 }
Exemplo n.º 43
0
 public void StoreKnowledgeForScope(SyncKnowledge knowledge, ForgottenKnowledge forgottenKnowledge)
 {
     _metadataStore.Metadata.SetKnowledge(knowledge);
     _metadataStore.Metadata.SetForgottenKnowledge(forgottenKnowledge);
     _metadataStore.Metadata.SaveReplicaMetadata();
 }
Exemplo n.º 44
0
 public void SaveConstraintConflict(
     ItemChange conflictingChange, 
     SyncId conflictingItemId,
     ConstraintConflictReason reason, 
     object conflictingChangeData,
     SyncKnowledge conflictingChangeKnowledge, 
     bool temporary)
 {
     var i = 1;
     // just to implement the interface
 }
Exemplo n.º 45
0
        public SyncKnowledge ProjectOnKnowledge( SyncKnowledge sourceKnowledge )
        {
            SyncKnowledge cumulativeKnowledge = null;

            foreach( BatchRange curRange in _ranges ) {
                if( !curRange.RangeIsUsable ) {
                    // break on last range if it is not usable
                    Debug.Assert( curRange == Last );
                    break; 
                }
                SyncKnowledge knowledgeForUnion = 
                    sourceKnowledge.GetKnowledgeForRange(curRange.Start, curRange.End);
                
                if( cumulativeKnowledge == null ) {
                    cumulativeKnowledge = knowledgeForUnion;
                } else {
                    cumulativeKnowledge.Combine( knowledgeForUnion );
                }
            }
            return cumulativeKnowledge;
        }
Exemplo n.º 46
0
 public override FullEnumerationChangeBatch GetFullEnumerationChangeBatch(uint batchSize, SyncId lowerEnumerationBound, SyncKnowledge knowledgeForDataRetrieval, out object changeDataRetriever)
 {
     throw new NotImplementedException("The method or operation is not implemented.");
 }
Exemplo n.º 47
0
        public void Load()
        {
            string syncFile = Path.Combine(folderPath, "file.sync");

            if (File.Exists(syncFile))
            {
                using (FileStream stream = new FileStream(syncFile, FileMode.Open))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    replicaId = (SyncId)bf.Deserialize(stream);
                    tickCount = (ulong)bf.Deserialize(stream);
                    myKnowledge = (SyncKnowledge)bf.Deserialize(stream);
                    if (myKnowledge.ReplicaId != ReplicaId)
                        throw new Exception("Replica id of loaded knowledge doesn't match replica id provided in constructor.");
                    myForgottenKnowledge = (ForgottenKnowledge)bf.Deserialize(stream);
                    if (myForgottenKnowledge.ReplicaId != ReplicaId)
                        throw new Exception("Replica id of loaded forgotten knowledge doesn't match replica id provided in constructor.");

                    System.Diagnostics.Debug.WriteLine("    ### Loaded For: " + folderPath + "  # Now Load metadatastore");
                    metadataStore.Load(stream);

                    System.Diagnostics.Debug.WriteLine("    ### End load Knowledge ###");
                }
                FindLocalFileChanges(folderPath);
            }
            else
            {
                replicaId = new SyncId(Guid.NewGuid());
                myKnowledge = new SyncKnowledge(IdFormats, ReplicaId, tickCount);
                myForgottenKnowledge = new ForgottenKnowledge(IdFormats, myKnowledge);
            }
        }
Exemplo n.º 48
0
        public override void GetSyncBatchParameters(out uint batchSize, out SyncKnowledge knowledge)
        {
            if (sync == null)
                throw new InvalidOperationException("Knowledge not yet loaded.");

            sync.SetLocalTickCount();

            batchSize = RequestedBatchSize;

            knowledge = sync.SyncKnowledge.Clone();
        }
Exemplo n.º 49
0
        public void StoreKnowledgeForScope(SyncKnowledge knowledge, ForgottenKnowledge forgottenKnowledge)
        {
            myKnowledge = knowledge;
            myForgottenKnowledge = forgottenKnowledge;

            Save();
        }
Exemplo n.º 50
0
 public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
 {
     return sync.GetChangeBatch(batchSize, destinationKnowledge, out changeDataRetriever);
 }
Exemplo n.º 51
0
 public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
 {
     ChangeBatch batch = _metadataStore.Metadata.GetChangeBatch(batchSize, destinationKnowledge);
     changeDataRetriever = _changeApplier;
     return batch;
 }
Exemplo n.º 52
0
 public void StoreKnowledgeForScope(SyncKnowledge knowledge, ForgottenKnowledge forgottenKnowledge)
 {
     sync.SyncKnowledge = knowledge;
     sync.ForgottenKnowledge = forgottenKnowledge;
     System.Diagnostics.Debug.WriteLine("Local.StoreKnowledgeForScope:" + knowledge + "ForgottenKnowledge:" + forgottenKnowledge);
 }
Exemplo n.º 53
0
 public override void GetSyncBatchParameters(out uint batchSize, out SyncKnowledge knowledge)
 {
     batchSize = 10;
     knowledge = _metadataStore.Metadata.GetKnowledge();
 }
Exemplo n.º 54
0
 public void SaveConstraintConflict(ItemChange conflictingChange, SyncId conflictingItemId, ConstraintConflictReason reason, object conflictingChangeData, SyncKnowledge conflictingChangeKnowledge, bool temporary)
 {
     throw new NotImplementedException();
 }
Exemplo n.º 55
0
        public static string GetSyncReplicaString(SyncKnowledge knowlege)
        {
            String retVal = "";

            MemoryStream memStream = new MemoryStream();
            XmlTextWriter writer = new XmlTextWriter(memStream, Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            knowlege.WriteXml(writer);
            writer.Flush();
            memStream.Seek(0, SeekOrigin.Begin);
            StreamReader reader = new StreamReader(memStream);
            retVal = reader.ReadToEnd();

            return retVal;
        }
Exemplo n.º 56
0
 public override void GetSyncBatchParameters(out uint batchSize, out SyncKnowledge knowledge)
 {
     batchSize = RequestedBatchSize;
     myKnowledge = sync.SyncKnowledge;
     knowledge = myKnowledge.Clone();
 }
        /// <summary>
        /// The way the current P2P provider works, versions are bumped up when conflicts are resolved on the server.
        /// This would result in us sending the changes to the client on the next download request. We want
        /// to not enumerate that change again. So one solution is to get the server knowledge after all changes are applied and then
        /// project the knowledge of each conflict and add it as a positive exception to the updated client knowledge.
        /// </summary>
        /// <param name="updatedClientKnowledge">Knowledge that is going to be sent to the client in the response</param>
        /// <param name="serverKnowledge">Server knowledge after applying changes</param>
        private void AddConflictItemsKnowledgeToClientKnowledge(SyncKnowledge updatedClientKnowledge, SyncKnowledge serverKnowledge)
        {
            foreach (var conflict in _conflicts)
            {
                SyncId entitySyncId;

                _conflictToSyncEntityIdMapping.TryGetValue(conflict, out entitySyncId);

                if (null == entitySyncId)
                {
                    throw new InvalidOperationException("SyncId is missing for a conflicting entity.");
                }

                // Create a new SyncKnowledge which only includes the server replica and set the local tickcount to
                // the value of @@DBTS that was read before committing the Apply transaction.
                var localKnowledge = new SyncKnowledge(serverKnowledge.GetSyncIdFormatGroup(),
                                                       serverKnowledge.ReplicaId,
                                                       _serverTickCountAfterResolvingAllConflicts);

                // Add the knowledge of the conflicting item to the client knowledge. This will be 
                // sent back to the client. In the next download request, the conflicting item will
                // not be enumerated since it is already contained in the knowledge.
                // After enumeration the knowledge is compacted and the single item positive exception
                // is removed.
                // Note: If there are a lot of conflicts, the knowledge sent back to the client will be 
                // large for that one instance. However the size will is not very significant compared to the amount
                // of data that is sent back in the response in the winning and the losing entities. 
                // The large knowledge in this case will be compacted on a subsequent download from the same client.

                // Project the knowledge of the single row from the created knowledge and combine it with
                // the updated client knowledge. This will add a positive exception since the server tickcount in the 
                // knowledge that is created (localKnowledge) is newer than that in the updatedClientKnowledge.
                updatedClientKnowledge.Combine(localKnowledge.GetKnowledgeForItem(entitySyncId));
            }
        }
Exemplo n.º 58
0
 //This is only called when the engine has detected that the destination is out of date due to Tombstone cleanup.
 public override FullEnumerationChangeBatch GetFullEnumerationChangeBatch(uint batchSize, SyncId lowerEnumerationBound, SyncKnowledge knowledgeForDataRetrieval, out object changeDataRetriever)
 {
     if(!_fullEnumFirstCall)
     {
         _syncItemCount = (uint)_store.Ids.Count;
         _fullEnumFirstCall = true;
     }
     FullEnumerationChangeBatch batch = _metadata.GetFullEnumerationChangeBatch(batchSize, lowerEnumerationBound, knowledgeForDataRetrieval);
     changeDataRetriever = this; //this is where the transfer mechanism/protocol would go. For an in memory provider, this is sufficient
     uint changesCount = 0;
     foreach (ItemChange itemChange in batch)
     {
         changesCount++;
     }
     batch.RemainingSessionWorkEstimate = _syncItemCount;
     batch.BatchWorkEstimate =  batch.IsLastBatch ? changesCount : batchSize;
     _syncItemCount = batch.IsLastBatch ? 0 : _syncItemCount - batchSize;
     return batch;
 }
        /// <summary>
        /// Get a new instance of the RowSorter class using the knowledge passed as a parameter. 
        /// This is used to pull out sorted batches with learned knowledge to send to the client.
        /// </summary>
        /// <param name="clientKnowledge">Knowledge to initialize the RowSorter instance.</param>
        /// <returns>An instance of the RowSorter class.</returns>
        private RowSorter GetRowSorter(SyncKnowledge clientKnowledge)
        {
            DbSyncScopeDescription scopeDescription = GetScopeDescription();
            Debug.Assert(null != scopeDescription);

            /* Note: The RowSorter class and dependencies are copied over from the 2.1 providers. 
             * If an when we decide to make this assembly a friend of the provider assembly,
             * we can remove the local copy of the source code. 
            */

            // Initialize an instance of the RowSorter class. 
            var rowSorter = new RowSorter(clientKnowledge, _clientScopeName, _configuration.DownloadBatchSizeInKB.Value);

            // Add all the tables to the RowSorter instance.
            foreach (DbSyncTableDescription table in scopeDescription.Tables)
            {
                // Get primary keys.
                List<string> pkColumns = table.PkColumns.Select(c => c.UnquotedName).ToList();

                // Set up the tables in the RowSorter class. 
                // The DataTable names will be equal to the UnquotedGlobalName // property value.
                rowSorter.AddTable(table.UnquotedGlobalName, pkColumns);
            }

            return rowSorter;
        }
Exemplo n.º 60
0
 public void SaveConflict(ItemChange conflictingChange, object conflictingChangeData, SyncKnowledge conflictingChangeKnowledge)
 {
     throw new NotImplementedException("The method or operation is not implemented.");
 }