1
votes

I synchronize two remote databases (Sql Express and Sql Compact) using sync framework 2.1 over WCF (N-Tier), using batching.

Recently I receive this log file, this is an error that appears quite rarely, but when it does it creates a lot of problem (it seems the tables from the data included in this sync scope that fails is deleted). I am positive sure nobody is messing with the BatchingDirectory so it should be there and contain all the data. Could the error below be related to the fact that I have

CleanupBatchingDirectory = true

and this is delete before the chages are applied?

11/06/2012 14:16:49 Error ** :PosPosSync:ThreadId=7: **: 
SyncScope ErpProduct  failed
Message: An unexpected error occurred when applying batch file C:\Documents and Settings\kasse6\Application Data\POSSyncDataClient\PosSync_5b009e9008c14d0ba6a9e47726d8d620\4e77ef8c-3045-4c55-809f-014ae2b96155.batch. See the inner exception for more details.
Type   : Microsoft.Synchronization.Data.DbSyncException
Stack  :    at Microsoft.Synchronization.Data.DbSyncBatchConsumer.ApplyBatches(DbSyncScopeMetadata scopeMetadata, DbSyncSession syncSession, SyncSessionStatistics sessionStatistics)
   at Microsoft.Synchronization.Data.RelationalSyncProvider.ProcessChangeBatch(ConflictResolutionPolicy resolutionPolicy, ChangeBatch sourceChanges, Object changeDataRetriever, SyncCallbacks syncCallbacks, SyncSessionStatistics sessionStatistics)
   at Microsoft.Synchronization.KnowledgeProviderProxy.ProcessChangeBatch(CONFLICT_RESOLUTION_POLICY resolutionPolicy, ISyncChangeBatch pSourceChangeManager, Object pUnkDataRetriever, ISyncCallback pCallback, _SYNC_SESSION_STATISTICS& pSyncSessionStatistics)
   at Microsoft.Synchronization.CoreInterop.ISyncSession.Start(CONFLICT_RESOLUTION_POLICY resolutionPolicy, _SYNC_SESSION_STATISTICS& pSyncSessionStatistics)
   at Microsoft.Synchronization.KnowledgeSyncOrchestrator.DoOneWaySyncHelper(SyncIdFormatGroup sourceIdFormats, SyncIdFormatGroup destinationIdFormats, KnowledgeSyncProviderConfiguration destinationConfiguration, SyncCallbacks DestinationCallbacks, ISyncProvider sourceProxy, ISyncProvider destinationProxy, ChangeDataAdapter callbackChangeDataAdapter, SyncDataConverter conflictDataConverter, Int32& changesApplied, Int32& changesFailed)
   at Microsoft.Synchronization.KnowledgeSyncOrchestrator.DoOneWayKnowledgeSync(SyncDataConverter sourceConverter, SyncDataConverter destinationConverter, SyncProvider sourceProvider, SyncProvider destinationProvider, Int32& changesApplied, Int32& changesFailed)
   at Microsoft.Synchronization.KnowledgeSyncOrchestrator.Synchronize()
   at Microsoft.Synchronization.SyncOrchestrator.Synchronize()
   at PosPosSync.Local.PosPosSyncService.SynchronizeProviders(KnowledgeSyncProvider localProvider, KnowledgeSyncProvider remoteProvider, SyncDirectionOrder syncDirectionOrder)
   at PosPosSync.Local.PosPosSyncService.SyncronizeData(String scopeName, SyncDirectionOrder syncDirectionOrder)
Source : Microsoft.Synchronization
Target : Void Start(CONFLICT_RESOLUTION_POLICY, _SYNC_SESSION_STATISTICS ByRef)
------- Inner Exception ------
    Message: Could not find a part of the path 'C:\Documents and Settings\kasse6\Application Data\POSSyncDataClient\PosSync_5b009e9008c14d0ba6a9e47726d8d620\4e77ef8c-3045-4c55-809f-014ae2b96155.batch'.
    Type   : System.IO.DirectoryNotFoundException
    Stack  :    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode)
   at Microsoft.Synchronization.Data.DbSyncBatchInfoFactory.Deserialize(String batchFileName, Boolean deserializeData)
   at Microsoft.Synchronization.Data.DbSyncBatchConsumer.ReadBatchFile(UInt32 lookupLocation, UInt32 expectedNumber)
   at Microsoft.Synchronization.Data.DbSyncBatchConsumer.ReadBatchFile(UInt32 expectedNumber, String& batchFileName)
   at Microsoft.Synchronization.Data.DbSyncBatchConsumer.ApplyBatches(DbSyncScopeMetadata scopeMetadata, DbSyncSession syncSession, SyncSessionStatistics sessionStatistics)
    Source : mscorlib
    Target : Void WinIOError(Int32, System.String)

The think is that after some time it tries to synchronize again all the data, and based on the log information I have, it seems it downloads everything from the client to the server:

11/06/2012 14:26:02 Info ** :PosPosSync:ThreadId=7: **: 
EndSync: ScopeName: ErpProduct
DownloadChanges: Applied - Failed: 122363 - 0
UploadChanges: Applied - Failed:  0 - 0
FinishedSync: ElapsedTime, sec: 545,0086488
2
is that the correct batching directory you specified? "it seems the tables from the data included in this sync scope that fails is deleted" - the framework never deletes user tables. your error is on the batch file. even if there's an error on the batch file, subsequent syncs should still work. - JuneT
Hi, the batching directory path is the one I specified. The problem is that when this error happens, the content of the table included in the scope is empty (is not the table that is deleted, but its content). I could not reproduce this on my machine, but this is the input I receive from the log files. - Angela_SB
you mean the table is being emptied after the error or you mean the table being synched is actually empty? - JuneT
Yes, for this scope ErpProduct, where the error happens, I only download data from SQL EXPRESS database to SQL Compact database. Between the first appears of the problem, I have some calls for some products (that should exist) directly to the database and nothing is found. And what confirms my fear is the message from the SyncOrchestrator: DownloadChanges: Applied - Failed: 122363 - 0 - Angela_SB
yes what? sync framework empties your table? or its really empty? Failed can mean either a conflict occurs or an error was encountered applying changes. subscribe to the ApplyChangeFailed event and see if its an error or a conflict - JuneT

2 Answers

0
votes

Try changing the SqlSyncProvider.MemoryDataCacheSize (Batch Size) on your client.

My client Synchronize was throwing the DirectoryNotFoundException when I set the Batch Size to 100kb, normally I run 500kb. I saw this only on large syncs (ex. initial sync of large database). Subsequent syncs worked fine as smaller).

UPDATE

According to MS Documentation issue could be caused by a database row exceeding 110% of the MemoryDataCacheSize.

The application specifies the memory data cache size for each provider that is participating in the synchronization session. If both providers specify a cache size, Sync Framework uses the smaller value for both providers. The actual cache size will be no more than 110% of the smallest specified size. During a synchronization session, if a single row is greater than 110% of the size the session terminates with an exception.

0
votes

After fighting with a similar issue for a few years I think I have finally found a solution.

This 'could not find a part of the path' issue also can happen if multiple scopes are defined (and the scopes are big enough to use batching), as there is a minor bug in the example code from MS. The issue is on Dispose in SqlWebSyncService, there is a deletion of the batching folder for this session but the directory info variable is not set to null (which is the test the next scope uses to know if it is making the folder or not). Adding in setting the batching directory to null fixes this issue, as when CheckAndCreateBatchingDirectory then runs through it finds the batching directory as null and goes through making it.

private void Dispose(bool disposing)
{
try
{
    if (!this.m_disposed)
    {
        if (disposing)
        {
            if (this.m_ServerProvider != null)
            {
                this.m_ServerProvider.Dispose();
                this.m_ServerProvider = null;
            }
            if (this.m_SessionBatchingDirectory != null)
            {
                this.m_SessionBatchingDirectory.Refresh();
                if (this.m_SessionBatchingDirectory.Exists)
                {
                    try
                    {
                        this.m_SessionBatchingDirectory.Delete(true);
                    }
                    catch
                    {
                    }
                }
                this.m_SessionBatchingDirectory = null;
            }
        }
        this.m_disposed = true;
    }
}
catch (Exception exception)
{
    string message = "SqlWebSyncService Cleanup Exception: " + exception;
    LogWriter.TraceError(message, new object[0]);
    throw new FaultException<WebSyncFaultException>(new WebSyncFaultException(message, exception));
}
}

Similarly on the client SqlSyncProviderProxy.EndSession

...
if (this.m_LocalBatchingDirectory != null) 
{
    this.m_LocalBatchingDirectory.Refresh();
    if (this.m_LocalBatchingDirectory.Exists) 
    {
       this.m_LocalBatchingDirectory.Delete(true);
    }
    this.m_LocalBatchingDirectory = null;
}
...

This behavior shows itself when changing batch size. We set our batch size large to 70000 and found the problem went away. In hindsight this is because the first scope then all fit in a single batch, so it did not get broken apart and implement batching. When we set the size smaller our first scope (1 of 3) would use batching and we'd see this when scope 2 fired up.