Beispiel #1
0
        // read and apply changes
        public IEnumerable <FsChangeResult> ReadAndApplyChanges(FileMaskList excludeList)
        {
            while (true)
            {
                var fsChange = Reader.ReadFsChange();
                if (fsChange.IsEmpty)
                {
                    break;
                }

                var fsChangeResult = ApplyFsChange(fsChange, excludeList);
                if (fsChangeResult.ResultCode != FsChangeResultCode.Ok && fsChange.ChangeType == FsChangeType.Change)
                {
                    var path = Path.Combine(BasePath, fsChange.Path);
                    if (fsChange.IsDirectory && File.Exists(path) ||
                        !fsChange.IsDirectory && Directory.Exists(path))
                    {
                        // delete and retry
                        var fsRemoveChangeResult = ApplyFsChange(
                            FsChange.CreateRemove(fsChange.Path),
                            excludeList);
                        if (fsRemoveChangeResult.ResultCode == FsChangeResultCode.Ok)
                        {
                            fsChangeResult = ApplyFsChange(fsChange, excludeList);
                        }
                    }
                }

                // TODO: skip ok codes (sender do not use them at the moment)
                if (fsChangeResult.ResultCode != FsChangeResultCode.Ok)
                {
                    yield return(fsChangeResult);
                }
            }
        }
Beispiel #2
0
        private void OnWatcherRenamed(object source, RenamedEventArgs e)
        {
            // ignore event for srcPath (don't know why it occurs rarely)
            if (e.FullPath == _srcPath || e.OldFullPath == _srcPath)
            {
                return;
            }

            var path    = GetPath(e.FullPath);
            var oldPath = GetPath(e.OldFullPath);

            if (_gitIsBusy && oldPath == GIT_INDEX_LOCK_FILENAME)
            {
                SetGitIsBusy(false);
            }

            // is new file excluded?
            if (_excludeList.IsMatch(path))
            {
                // old file is not excluded -> delete it
                if (!_excludeList.IsMatch(oldPath))
                {
                    AddChange(FsChange.CreateRemove(oldPath));
                }

                // both files are excluded -> do nothing
            }
            else // new file is not excluded
            {
                // old file is excluded -> send change with withSubdirectories
                if (_excludeList.IsMatch(oldPath))
                {
                    AddChange(FsChange.CreateChange(path), withSubdirectories: true);
                }
                else
                {
                    // both files are not excluded -> send rename
                    AddChange(FsChange.CreateRename(path, oldPath));
                }
            }
        }
Beispiel #3
0
        private void OnWatcherDeleted(object source, FileSystemEventArgs e)
        {
            // ignore event for srcPath (don't know why it occurs rarely)
            if (e.FullPath == _srcPath)
            {
                return;
            }

            var path = GetPath(e.FullPath);

            if (_gitIsBusy && path == GIT_INDEX_LOCK_FILENAME)
            {
                SetGitIsBusy(false);
            }

            if (_excludeList.IsMatch(path))
            {
                return;
            }

            AddChange(FsChange.CreateRemove(path));
        }
Beispiel #4
0
        private void Scan()
        {
            var            sw      = Stopwatch.StartNew();
            List <FsEntry> srcList = null;
            Dictionary <string, FsEntry> destList;

            /*
             * Start agent before scan source
             *
             * Old timeline: [Main thread]       Start ... Initialize ... Scan destination ... Finish
             *               [Secondary thread]  Scan source ................................. Finish
             *
             * New timeline: [Main thread]       Start ... Initialize ... Scan destination ... Finish
             *               [Secondary thread]            Scan source ....................... Finish
             *
             * A failed start could cause unnecessary scanning source in old timeline.
             * No need to scan source before start in most cases because it is about as fast as the scan destination.
             */
            _agentStarter.Start();

            using (var tokenSource = new CancellationTokenSource())
            {
                var cancellationToken = tokenSource.Token;

                // scan source
                var task = Task.Run(() =>
                {
                    try
                    {
                        var swScanSource  = Stopwatch.StartNew();
                        var scanDirectory =
                            new ScanDirectory(_logger, _excludeList, cancellationToken: cancellationToken);
                        srcList = scanDirectory.ScanPath(_srcPath).ToList();
                        cancellationToken.ThrowIfCancellationRequested();
                        _logger.Log($"Scanned source {srcList.Count} items in {swScanSource.ElapsedMilliseconds} ms");
                    }
                    catch (OperationCanceledException)
                    {
                        srcList = null;
                    }
                }, cancellationToken);

                try
                {
                    var swScanDestination = Stopwatch.StartNew();
                    // scan destination
                    var response = _agentStarter.SendCommand <ScanResponse>(new ScanRequest(_logger));
                    destList = response.FileList.ToDictionary(x => x.Path, y => y);
                    _logger.Log($"Scanned destination {destList.Count} items in {swScanDestination.ElapsedMilliseconds} ms");
                    task.Wait(cancellationToken);
                }
                catch (Exception)
                {
                    tokenSource.Cancel();
                    throw;
                }
            }

            // During scan, changes could come from file system events or from PathScanner, we should not overwrite them.
            var  itemsCount  = 0;
            long changesSize = 0;

            lock (_changes)
            {
                foreach (var srcEntry in srcList)
                {
                    if (!destList.TryGetValue(srcEntry.Path, out var destEntry))
                    {
                        destEntry = FsEntry.Empty;
                    }

                    // Skip changed srcEntry
                    if (!_changes.ContainsKey(srcEntry.Path))
                    {
                        // add to changes (no replace)
                        if (!srcEntry.Compare(destEntry))
                        {
                            itemsCount++;
                            if (!srcEntry.IsDirectory)
                            {
                                changesSize += srcEntry.Length;
                            }
                            AddChange(FsChange.CreateChange(srcEntry), false);
                        }
                    }

                    if (!destEntry.IsEmpty)
                    {
                        destList.Remove(destEntry.Path);
                    }
                }

                // add deletes
                foreach (var destEntry in destList.Values)
                {
                    // Skip changed destEntry
                    if (!_changes.ContainsKey(destEntry.Path))
                    {
                        itemsCount++;
                        AddChange(FsChange.CreateRemove(destEntry.Path), false);
                    }
                }
            }

            _needToScan = false;
            _logger.Log(
                $"Scanned in {sw.ElapsedMilliseconds} ms, {itemsCount} items, {PrettySize(changesSize)} to send");
            UpdateHasWork();
        }