/// <summary> /// ファイル監視で変更通知が行われた、ファイルの更新キューを更新する。 /// </summary> /// <remarks> /// 対象パスがキューに登録済みの場合は、登録情報の更新を行います。 /// 未登録の場合は、情報を新規登録します。 /// </remarks> /// <param name="watchTarget">変更通知が発生した、ファイル情報</param> /// <param name="watcherChangeType">変更内容区分</param> /// <param name="beforeRenamedName">変更内容区分がリネームの場合、リネーム前のファイル名を入力してください</param> FileUpdateQueueItem UpdateOrInsertUpdatedFileQueueItem(FileInfo watchTarget, WatcherChangeTypes watcherChangeType, string beforeRenamedName) { FileUpdateQueueItem fileUpdateQueueItem; string key; lock (this) { // 更新イベントの対象ファイルが、ACLファイルか物理ファイルか更新キューに使用するキーが異なる。 // ACLファイルでは、ACLハッシュをキーに使用します。 // 物理ファイルでは、ファイルパスをキーに使用します。 if (watchTarget.Extension == ".aclgene") { // ACLファイルの場合、更新イベントを追わなくてもACLハッシュで常にどのファイルが更新キュー内のどこにあるかがわかる // ※ただし、ファイル削除を除く if (watcherChangeType == WatcherChangeTypes.Deleted) { var deletedFileRelativePath = this._Workspace.TrimWorekspacePath(watchTarget.FullName, false); var r = from u in _UpdatesWatchFiles where u.Value.OldRenameNamePath == deletedFileRelativePath select u; var prop = r.FirstOrDefault(); if (prop.Key != null) { _UpdatesWatchFiles.TryGetValue(prop.Key, out fileUpdateQueueItem); } else { fileUpdateQueueItem = new FileUpdateQueueItem { Target = watchTarget }; _UpdatesWatchFiles.AddOrUpdate(deletedFileRelativePath, fileUpdateQueueItem, (_key, _value) => fileUpdateQueueItem ); // 発生はありえないが、発生した場合は処理せず終了 // →発生はありうる。 //LOG.Warn("更新キューに登録されていないACLファイルの削除イベント"); //return null; } } else { // ACLファイルからACLデータを取得 AclFileStructure aclFileData; using (var file = File.OpenRead(watchTarget.FullName)) { aclFileData = Serializer.Deserialize <AclFileStructure>(file); } var aclhash = aclFileData.FindKeyValue("ACLHASH"); if (!_UpdatesWatchFiles.ContainsKey(aclhash)) { fileUpdateQueueItem = new FileUpdateQueueItem { Target = watchTarget }; _UpdatesWatchFiles.AddOrUpdate(aclhash, fileUpdateQueueItem, (_key, _value) => fileUpdateQueueItem); } else { // キューから情報を取得 _UpdatesWatchFiles.TryGetValue(aclhash, out fileUpdateQueueItem); fileUpdateQueueItem.Target = watchTarget; // 登録している物理ファイル情報を最新のオブジェクトにする } // 最後に更新イベントが発生した時のファイルパスを格納しておく(Deleteイベント用) fileUpdateQueueItem.OldRenameNamePath = this._Workspace.TrimWorekspacePath(watchTarget.FullName, false); } } else { if (watcherChangeType == WatcherChangeTypes.Renamed && !string.IsNullOrEmpty(beforeRenamedName)) { // 変更内容がリネームの場合、名前変更前のファイルパスで登録済みの項目を取得し、 // 名前変更前の項目はキューから削除します。 // 名前変更後の項目として、新たにキューに再登録を行います。 var renamedFullName = watchTarget.FullName.Replace(watchTarget.FullName, beforeRenamedName); var oldkey = this._Workspace.TrimWorekspacePath(renamedFullName, false); key = this._Workspace.TrimWorekspacePath(watchTarget.FullName, false); if (_UpdatesWatchFiles.ContainsKey(oldkey)) { // 古いキーの項目をキューから削除します。 // 新しいキーで、キューに情報を再登録します。 _UpdatesWatchFiles.TryRemove(oldkey, out fileUpdateQueueItem); _UpdatesWatchFiles.AddOrUpdate(key, fileUpdateQueueItem, (_key, _value) => fileUpdateQueueItem); } } else if (watcherChangeType == WatcherChangeTypes.Created) { key = this._Workspace.TrimWorekspacePath(watchTarget.FullName, false); } else { key = this._Workspace.TrimWorekspacePath(watchTarget.FullName, false); } // 更新通知があったファイルが処理キューに未登録の場合、キューに更新通知情報を新規登録します if (!_UpdatesWatchFiles.ContainsKey(key)) { fileUpdateQueueItem = new FileUpdateQueueItem { Target = watchTarget }; _UpdatesWatchFiles.AddOrUpdate(key, fileUpdateQueueItem, (_key, _value) => fileUpdateQueueItem); } else { // キューから情報を取得 _UpdatesWatchFiles.TryGetValue(key, out fileUpdateQueueItem); fileUpdateQueueItem.Target = watchTarget; // 登録している物理ファイル情報を最新のオブジェクトにする } // 更新通知のイベント区分が『リネーム』の場合、元のファイル名も保存しておく。 // イベント処理前は物理ディレクトリ空間のファイルパスはリネーム前のパスのままなので、 // リネーム前のファイル名のみを保存します。 if (watcherChangeType == WatcherChangeTypes.Renamed && string.IsNullOrEmpty(fileUpdateQueueItem.OldRenameNamePath)) { fileUpdateQueueItem.OldRenameNamePath = beforeRenamedName; } } // 情報に、履歴を追加 var now = DateTime.Now; fileUpdateQueueItem.LastUpdate = now; var rec = new RecentInfo { EventType = watcherChangeType, RecentDate = now }; fileUpdateQueueItem.Recents.Add(rec); return(fileUpdateQueueItem); } }
/// <summary> /// インデックス作成処理を一定間隔で行います /// </summary> /// <param name="sender"></param> /// <param name="e"></param> async void OnIndexTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) { if (this.IsSuspendIndex) { return; // サスペンド時はインデックス生成処理はスキップする } // インデックス生成処理中は、このメソッドを呼び出すタイマーは停止しておきます。 var timer = sender as System.Timers.Timer; timer.Enabled = false; LOG.Info("タイマー処理の実行"); // ディレクトリ削除イベントが発生している場合、 // 削除したディレクトリに含まれていたファイルを、削除したパスから見つけ出して削除処理を行うキューに追加する lock (sameDirectoryOperation_Locker) { if (sameDirectoryOperation_Name != "") { sameDirectoryOperation_Name = ""; var relativeDirPath = _Workspace.TrimWorekspacePath(sameDirectoryOperation_FullPath, false); using (var dbc = new AppDbContext()) { var repo = new FileMappingInfoRepository(dbc); foreach (var prop in repo.FindBy(p => p.MappingFilePath.StartsWith(relativeDirPath))) { var fileUpdateQueueItem = new FileUpdateQueueItem { Target = new FileInfo(Path.Combine(_Workspace.WorkspacePath, prop.MappingFilePath + ".aclgene")) }; fileUpdateQueueItem.Recents.Add(new RecentInfo { EventType = WatcherChangeTypes.Deleted }); _UpdatesWatchFiles.AddOrUpdate(prop.MappingFilePath, fileUpdateQueueItem, (_key, _value) => fileUpdateQueueItem); } } } } // foreach (var @pair in _UpdatesWatchFiles.ToList()) { // 最後のファイル監視状態から、一定時間経過している場合のみ処理を行う。 var @diff = DateTime.Now - @pair.Value.LastUpdate; if (@diff.Seconds >= 10) // 10秒 以上経過 { FileUpdateQueueItem item; // work if (_UpdatesWatchFiles.TryRemove(@pair.Key, out item)) { var @lastItem = item.Recents.LastOrDefault(); // NOTE: UpdateVirtualSpaceFlowワークフローを呼び出す LOG.InfoFormat("ワークフロー実行 [{1}] 対象ファイルパス={0}", item.Target.FullName, @lastItem.EventType); // ワークフロー処理中に発生するファイル更新イベントにより、更新キューに項目が追加されてしまうことを防ぐため、 // 処理中のファイルを更新キューから除外するための除外リストに、処理中のファイルを追加する。 // // ※処理中のファイルがACLファイル以外の場合、対象ファイルのACLファイル名も除外リストに追加する _IgnoreUpdateFiles.Enqueue(item.Target.FullName); if (item.Target.Extension != ".aclgene") { _IgnoreUpdateFiles.Enqueue(item.Target.FullName + ".aclgene"); } try { using (var dbc = new AppDbContext()) { var workspace = WorkspaceRepository.Load(dbc, _Workspace.Id); var workflow = new WorkflowInvoker(new UpdateVirtualSpaceAppFlow()); workflow.Extensions.Add(new WorkflowExtention(dbc)); var pstack = new ParameterStack(); // 処理対象のファイルがACLファイルか、物理ファイルかで処理を切り分けます // ■ACLファイルの場合 // リネーム更新イベントに対応します。 // ■物理ファイルの場合 // リネーム更新イベントも、UPDATEイベントとして処理します。 if (item.Target.Extension == ".aclgene") { var fileNameWithputExtension = item.Target.Name.Replace(item.Target.Extension, ""); switch (@lastItem.EventType) { case WatcherChangeTypes.Renamed: pstack.SetValue("Event", Mogami.Core.Constructions.UpdateVirtualStatusEventType.RENAME); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEINFO, item.Target); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEPATH, item.Target.Name); // リネーム後のファイル名 pstack.SetValue(ActivityParameterStack.WORKSPACE, workspace); var results_renamed = workflow.Invoke(new Dictionary <string, object> { { "ParameterStack", pstack }, //{"EventType", UpdateVirtualStatusEventType.RENAME}, //{"Target", item.Target}, //{"BeforeRenameName",item.OldRenameNamePath}, //{"Workspace", workspace} }); break; case WatcherChangeTypes.Changed: case WatcherChangeTypes.Created: var aclfileLocalPath = workspace.TrimWorekspacePath(item.Target.FullName, false); pstack.SetValue("Event", Mogami.Core.Constructions.UpdateVirtualStatusEventType.UPDATE); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEINFO, item.Target); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEPATH, aclfileLocalPath); // 移動後のファイルパス pstack.SetValue(ActivityParameterStack.WORKSPACE, workspace); var results_changed = workflow.Invoke(new Dictionary <string, object> { { "ParameterStack", pstack }, //{"EventType", UpdateVirtualStatusEventType.UPDATE}, //{"Target", item.Target}, //{"Workspace", workspace} }); break; case WatcherChangeTypes.Deleted: var aclfileLocalPath_Delete = workspace.TrimWorekspacePath(item.Target.FullName, false); pstack.SetValue("Event", Mogami.Core.Constructions.UpdateVirtualStatusEventType.DELETE); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEINFO, item.Target); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEPATH, aclfileLocalPath_Delete); // 削除したファイル pstack.SetValue(ActivityParameterStack.WORKSPACE, workspace); pstack.SetValue("WF_DeleteAclMappingFilePath", fileNameWithputExtension); var results_deleted = workflow.Invoke(new Dictionary <string, object> { { "ParameterStack", pstack }, //{"EventType", UpdateVirtualStatusEventType.DELETE}, //{"Target", item.Target}, //{"DeleteAclHash", @pair.Key}, //{"Workspace", workspace} }); break; } } else { if (File.Exists(item.Target.FullName)) { switch (@lastItem.EventType) { case WatcherChangeTypes.Renamed: case WatcherChangeTypes.Changed: case WatcherChangeTypes.Created: var aclfileLocalPath_Update = workspace.TrimWorekspacePath(item.Target.FullName, false); pstack.SetValue("Event", Mogami.Core.Constructions.UpdateVirtualStatusEventType.UPDATE); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEINFO, item.Target); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEPATH, aclfileLocalPath_Update); // 削除したファイル pstack.SetValue(ActivityParameterStack.WORKSPACE, workspace); var results_changed = workflow.Invoke(new Dictionary <string, object> { { "ParameterStack", pstack }, //{"EventType", UpdateVirtualStatusEventType.UPDATE}, //{"Target", item.Target}, //{"Workspace", workspace} }); break; case WatcherChangeTypes.Deleted: var aclfileLocalPath_Delete = workspace.TrimWorekspacePath(item.Target.FullName, false); pstack.SetValue("Event", Mogami.Core.Constructions.UpdateVirtualStatusEventType.DELETE); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEINFO, item.Target); pstack.SetValue(ActivityParameterStack.WORKSPACE_FILEPATH, aclfileLocalPath_Delete); // 削除したファイル pstack.SetValue(ActivityParameterStack.WORKSPACE, workspace); var results_deleted = workflow.Invoke(new Dictionary <string, object> { { "ParameterStack", pstack }, //{"EventType", UpdateVirtualStatusEventType.DELETE}, //{"Target", item.Target}, //{"Workspace", workspace} }); break; } } else { LOG.InfoFormat("「{0}」は存在しない物理ファイルのため、処理をスキップします。", item.Target.FullName); } } dbc.SaveChanges(); } } catch (Exception expr) { LOG.ErrorFormat("タイマー処理時エラー = {0}", expr.Message); } // 処理を終了したファイルを、除外リストから削除します string ignoreUpdateFile; _IgnoreUpdateFiles.TryDequeue(out ignoreUpdateFile); if (item.Target.Extension != ".aclgene") { _IgnoreUpdateFiles.TryDequeue(out ignoreUpdateFile); } } } // [CPU使用率に対するループ遅延を行う] var cpuPer = _CpuCounter.NextValue(); if (cpuPer > 90.0) { await Task.Delay(100); // 100msec待機 } else if (cpuPer > 30.0) { //await Task.Delay(10); // 10msec待機 } } timer.Enabled = true; }