public void EnqueueSynchronization(string destination, SynchronizationWorkItem workItem)
{
pendingRemoveLocks.GetOrAdd(destination, new ReaderWriterLockSlim()).EnterUpgradeableReadLock();
try
{
var pendingForDestination = pendingSynchronizations.GetOrAdd(destination,
new ConcurrentQueue<SynchronizationWorkItem>());
// if delete work is enqueued and there are other synchronization works for a given file then remove them from a queue
if (workItem.SynchronizationType == SynchronizationType.Delete &&
pendingForDestination.Any(
x => x.FileName == workItem.FileName && x.SynchronizationType != SynchronizationType.Delete))
{
pendingRemoveLocks.GetOrAdd(destination, new ReaderWriterLockSlim()).EnterWriteLock();
try
{
var modifiedQueue = new ConcurrentQueue<SynchronizationWorkItem>();
foreach (var pendingWork in pendingForDestination)
{
if (pendingWork.FileName != workItem.FileName)
modifiedQueue.Enqueue(pendingWork);
}
modifiedQueue.Enqueue(workItem);
pendingForDestination = pendingSynchronizations.AddOrUpdate(destination, modifiedQueue,
(key, value) => modifiedQueue);
}
finally
{
pendingRemoveLocks.GetOrAdd(destination, new ReaderWriterLockSlim()).ExitWriteLock();
}
}
foreach (var pendingWork in pendingForDestination)
{
// if there is a file in pending synchronizations do not add it again
if (pendingWork.Equals(workItem))
{
Log.Debug("{0} for a file {1} and a destination {2} was already existed in a pending queue",
workItem.GetType().Name, workItem.FileName, destination);
return;
}
// if there is a work for a file of the same type but with lower file ETag just refresh existing work metadata and do not enqueue again
if (pendingWork.FileName == workItem.FileName &&
pendingWork.SynchronizationType == workItem.SynchronizationType &&
Buffers.Compare(workItem.FileETag.ToByteArray(), pendingWork.FileETag.ToByteArray()) > 0)
{
pendingWork.RefreshMetadata();
Log.Debug(
"{0} for a file {1} and a destination {2} was already existed in a pending queue but with older ETag, it's metadata has been refreshed",
workItem.GetType().Name, workItem.FileName, destination);
return;
}
}
var activeForDestination = activeSynchronizations.GetOrAdd(destination,
new ConcurrentDictionary<string, SynchronizationWorkItem>
());
// if there is a work in an active synchronizations do not add it again
if (activeForDestination.ContainsKey(workItem.FileName) && activeForDestination[workItem.FileName].Equals(workItem))
{
Log.Debug("{0} for a file {1} and a destination {2} was already existed in an active queue",
workItem.GetType().Name, workItem.FileName, destination);
return;
}
pendingForDestination.Enqueue(workItem);
Log.Debug("{0} for a file {1} and a destination {2} was enqueued", workItem.GetType().Name, workItem.FileName,
destination);
}
finally
{
pendingRemoveLocks.GetOrAdd(destination, new ReaderWriterLockSlim()).ExitUpgradeableReadLock();
}
}