// 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); } } }
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)); } } }
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)); }
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(); }