From 9560277d0c9d4e3f4153347bc8bf24f6d42f0c69 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Thu, 5 Sep 2024 12:10:42 +0800 Subject: [PATCH 1/3] :recycle: Implement some delayed kernel events using task queues https://github.com/siyuan-note/siyuan/issues/12393 --- kernel/api/av.go | 14 ++-- kernel/model/attribute_view.go | 24 +++++-- kernel/model/file.go | 2 +- kernel/model/history.go | 2 +- kernel/model/transaction.go | 8 +-- kernel/task/queue.go | 116 +++++++++++++++++++++------------ kernel/util/websocket.go | 4 -- 7 files changed, 105 insertions(+), 65 deletions(-) diff --git a/kernel/api/av.go b/kernel/api/av.go index da8d97e60..b311f4dbb 100644 --- a/kernel/api/av.go +++ b/kernel/api/av.go @@ -212,7 +212,7 @@ func addAttributeViewBlocks(c *gin.Context) { return } - util.PushReloadAttrView(avID) + model.ReloadAttrView(avID) } func removeAttributeViewBlocks(c *gin.Context) { @@ -237,7 +237,7 @@ func removeAttributeViewBlocks(c *gin.Context) { return } - util.PushReloadAttrView(avID) + model.ReloadAttrView(avID) } func addAttributeViewKey(c *gin.Context) { @@ -263,7 +263,7 @@ func addAttributeViewKey(c *gin.Context) { return } - util.PushReloadAttrView(avID) + model.ReloadAttrView(avID) } func removeAttributeViewKey(c *gin.Context) { @@ -285,7 +285,7 @@ func removeAttributeViewKey(c *gin.Context) { return } - util.PushReloadAttrView(avID) + model.ReloadAttrView(avID) } func sortAttributeViewViewKey(c *gin.Context) { @@ -312,7 +312,7 @@ func sortAttributeViewViewKey(c *gin.Context) { return } - util.PushReloadAttrView(avID) + model.ReloadAttrView(avID) } func sortAttributeViewKey(c *gin.Context) { @@ -335,7 +335,7 @@ func sortAttributeViewKey(c *gin.Context) { return } - util.PushReloadAttrView(avID) + model.ReloadAttrView(avID) } func getAttributeViewFilterSort(c *gin.Context) { @@ -609,5 +609,5 @@ func setAttributeViewBlockAttr(c *gin.Context) { blockAttributeViewKeys := model.UpdateAttributeViewCell(nil, avID, keyID, rowID, cellID, value) ret.Data = blockAttributeViewKeys - util.PushReloadAttrView(avID) + model.ReloadAttrView(avID) } diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 9f0c1769b..c3a334e89 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -19,6 +19,7 @@ package model import ( "bytes" "fmt" + "github.com/siyuan-note/siyuan/kernel/task" "os" "path/filepath" "slices" @@ -92,7 +93,7 @@ func AppendAttributeViewDetachedBlocksWithValues(avID string, blocksValues [][]* return } - util.PushReloadAttrView(avID) + ReloadAttrView(avID) return } @@ -1044,7 +1045,7 @@ func unbindAttributeViewBlock(operation *Operation, tx *Transaction) (err error) changedAvIDs = gulu.Str.RemoveDuplicatedElem(changedAvIDs) for _, avID := range changedAvIDs { - util.PushReloadAttrView(avID) + ReloadAttrView(avID) } return } @@ -1313,7 +1314,7 @@ func updateAttributeViewColRelation(operation *Operation) (err error) { } if !isSameAv { err = av.SaveAttributeView(destAv) - util.PushReloadAttrView(destAv.ID) + ReloadAttrView(destAv.ID) } av.UpsertAvBackRel(srcAv.ID, destAv.ID) @@ -2147,7 +2148,7 @@ func removeAttributeViewBlock(srcIDs []string, avID string, tx *Transaction) (er relatedAvIDs := av.GetSrcAvIDs(avID) for _, relatedAvID := range relatedAvIDs { - util.PushReloadAttrView(relatedAvID) + ReloadAttrView(relatedAvID) } err = av.SaveAttributeView(attrView) @@ -2804,7 +2805,7 @@ func RemoveAttributeViewKey(avID, keyID string) (err error) { if destAv != attrView { av.SaveAttributeView(destAv) - util.PushReloadAttrView(destAv.ID) + ReloadAttrView(destAv.ID) } if !destAvRelSrcAv { @@ -2940,7 +2941,7 @@ func replaceAttributeViewBlock(operation *Operation, tx *Transaction) (err error changedAvIDs = gulu.Str.RemoveDuplicatedElem(changedAvIDs) for _, avID := range changedAvIDs { - util.PushReloadAttrView(avID) + ReloadAttrView(avID) } return } @@ -3182,7 +3183,7 @@ func UpdateAttributeViewCell(tx *Transaction, avID, keyID, rowID, cellID string, relatedAvIDs := av.GetSrcAvIDs(avID) for _, relatedAvID := range relatedAvIDs { - util.PushReloadAttrView(relatedAvID) + ReloadAttrView(relatedAvID) } if err = av.SaveAttributeView(attrView); err != nil { @@ -3579,3 +3580,12 @@ func updateBoundBlockAvsAttribute(avIDs []string) { av.BatchUpsertBlockRel(avNodes) } } + +func ReloadAttrView(avID string) { + task.AppendTaskWithDelay(task.ReloadAttributeView, 200*time.Millisecond, pushReloadAttrView, avID) + +} + +func pushReloadAttrView(avID string) { + util.BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": avID}) +} diff --git a/kernel/model/file.go b/kernel/model/file.go index bf83d133d..48ef74edb 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -1113,7 +1113,7 @@ func DuplicateDoc(tree *parse.Tree) { "id": n.ID, "isDetached": false, }}, avID, "", "", false) - util.PushReloadAttrView(avID) + ReloadAttrView(avID) } return ast.WalkContinue }) diff --git a/kernel/model/history.go b/kernel/model/history.go index 1685a99ed..95069cd23 100644 --- a/kernel/model/history.go +++ b/kernel/model/history.go @@ -312,7 +312,7 @@ func RollbackDocHistory(boxID, historyPath string) (err error) { // 刷新属性视图 for _, avID := range avIDs { - util.PushReloadAttrView(avID) + ReloadAttrView(avID) } }() return nil diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index 3bcc5c297..d29761f4e 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -813,7 +813,7 @@ func syncDelete2AvBlock(node *ast.Node) { go func() { time.Sleep(256 * time.Millisecond) for _, avID := range changedAvIDs { - util.PushReloadAttrView(avID) + ReloadAttrView(avID) } }() } @@ -1074,7 +1074,7 @@ func (tx *Transaction) doInsert(operation *Operation) (ret *TxErr) { "id": insertedNode.ID, "isDetached": false, }}, avID, "", previousID, false) - util.PushReloadAttrView(avID) + ReloadAttrView(avID) } operation.ID = insertedNode.ID @@ -1187,7 +1187,7 @@ func upsertAvBlockRel(node *ast.Node) { }) avIDs = gulu.Str.RemoveDuplicatedElem(avIDs) for _, avID := range avIDs { - util.PushReloadAttrView(avID) + ReloadAttrView(avID) } } @@ -1533,7 +1533,7 @@ func refreshDynamicRefTexts(updatedDefNodes map[string]*ast.Node, updatedTrees m } if changedAv { av.SaveAttributeView(attrView) - util.PushReloadAttrView(avID) + ReloadAttrView(avID) } } } diff --git a/kernel/task/queue.go b/kernel/task/queue.go index 1e6d2e32e..49a53b887 100644 --- a/kernel/task/queue.go +++ b/kernel/task/queue.go @@ -37,50 +37,80 @@ type Task struct { Handler reflect.Value Args []interface{} Created time.Time + Delay time.Duration Timeout time.Duration } func AppendTask(action string, handler interface{}, args ...interface{}) { - AppendTaskWithTimeout(action, 24*time.Hour, handler, args...) + appendTaskWithDelayTimeout(action, 0, 24*time.Hour, handler, args...) +} + +func AppendTaskWithDelay(action string, delay time.Duration, handler interface{}, args ...interface{}) { + appendTaskWithDelayTimeout(action, delay, 24*time.Hour, handler, args...) } func AppendTaskWithTimeout(action string, timeout time.Duration, handler interface{}, args ...interface{}) { + appendTaskWithDelayTimeout(action, 0, timeout, handler, args...) +} + +func appendTaskWithDelayTimeout(action string, delay, timeout time.Duration, handler interface{}, args ...interface{}) { if util.IsExiting.Load() { //logging.LogWarnf("task queue is paused, action [%s] will be ignored", action) return } - currentActions := getCurrentActions() - if gulu.Str.Contains(action, currentActions) && gulu.Str.Contains(action, uniqueActions) { - //logging.LogWarnf("task [%s] is already in queue, will be ignored", action) - return + task := &Task{ + Action: action, + Handler: reflect.ValueOf(handler), + Args: args, + Created: time.Now(), + Delay: delay, + Timeout: timeout, + } + + if gulu.Str.Contains(action, uniqueActions) { + if currentTasks := getCurrentTasks(); containTask(task, currentTasks) { + //logging.LogWarnf("task [%s] is already in queue, will be ignored", action) + return + } } queueLock.Lock() defer queueLock.Unlock() - taskQueue = append(taskQueue, &Task{ - Action: action, - Timeout: timeout, - Handler: reflect.ValueOf(handler), - Args: args, - Created: time.Now(), - }) + taskQueue = append(taskQueue, task) } -func getCurrentActions() (ret []string) { - queueLock.Lock() +func containTask(task *Task, tasks []*Task) bool { + for _, t := range tasks { + if t.Action == task.Action { + if len(t.Args) != len(task.Args) { + return false + } - currentTaskActionLock.Lock() - if "" != currentTaskAction { - ret = append(ret, currentTaskAction) + for i, arg := range t.Args { + if arg != task.Args[i] { + return false + } + } + return true + } } - currentTaskActionLock.Unlock() + return false +} + +func getCurrentTasks() (ret []*Task) { + queueLock.Lock() + defer queueLock.Unlock() + + currentTaskLock.Lock() + if nil != currentTask { + ret = append(ret, currentTask) + } + currentTaskLock.Unlock() for _, task := range taskQueue { - ret = append(ret, task.Action) + ret = append(ret, task) } - - queueLock.Unlock() return } @@ -100,6 +130,7 @@ const ( AssetContentDatabaseIndexFull = "task.asset.database.index.full" // 资源文件数据库重建索引 AssetContentDatabaseIndexCommit = "task.asset.database.index.commit" // 资源文件数据库索引提交 CacheVirtualBlockRef = "task.cache.virtualBlockRef" // 缓存虚拟块引用 + ReloadAttributeView = "task.reload.attributeView" // 重新加载属性视图 ) // uniqueActions 描述了唯一的任务,即队列中只能存在一个在执行的任务。 @@ -116,9 +147,9 @@ var uniqueActions = []string{ } func ContainIndexTask() bool { - actions := getCurrentActions() - for _, action := range actions { - if gulu.Str.Contains(action, []string{DatabaseIndexFull, DatabaseIndex}) { + tasks := getCurrentTasks() + for _, task := range tasks { + if gulu.Str.Contains(task.Action, []string{DatabaseIndexFull, DatabaseIndex}) { return true } } @@ -150,15 +181,13 @@ func StatusJob() { } defer queueLock.Unlock() - currentTaskActionLock.Lock() - if "" != currentTaskAction { - if nil != actionLangs { - if label := actionLangs[currentTaskAction]; nil != label { - items = append([]map[string]interface{}{{"action": label.(string)}}, items...) - } + currentTaskLock.Lock() + if nil != currentTask && nil != actionLangs { + if label := actionLangs[currentTask.Action]; nil != label { + items = append([]map[string]interface{}{{"action": label.(string)}}, items...) } } - currentTaskActionLock.Unlock() + currentTaskLock.Unlock() if 1 > len(items) { items = []map[string]interface{}{} @@ -189,14 +218,19 @@ func popTask() (ret *Task) { return } - ret = taskQueue[0] - taskQueue = taskQueue[1:] + for i, task := range taskQueue { + if time.Since(task.Created) > task.Delay { + ret = task + taskQueue = append(taskQueue[:i], taskQueue[i+1:]...) + return + } + } return } var ( - currentTaskAction string - currentTaskActionLock = sync.Mutex{} + currentTask *Task + currentTaskLock = sync.Mutex{} ) func execTask(task *Task) { @@ -211,9 +245,9 @@ func execTask(task *Task) { } } - currentTaskActionLock.Lock() - currentTaskAction = task.Action - currentTaskActionLock.Unlock() + currentTaskLock.Lock() + currentTask = task + currentTaskLock.Unlock() ctx, cancel := context.WithTimeout(context.Background(), task.Timeout) defer cancel() @@ -230,7 +264,7 @@ func execTask(task *Task) { //logging.LogInfof("task [%s] done", task.Action) } - currentTaskActionLock.Lock() - currentTaskAction = "" - currentTaskActionLock.Unlock() + currentTaskLock.Lock() + currentTask = nil + currentTaskLock.Unlock() } diff --git a/kernel/util/websocket.go b/kernel/util/websocket.go index 139239029..7813f7976 100644 --- a/kernel/util/websocket.go +++ b/kernel/util/websocket.go @@ -240,10 +240,6 @@ func PushClearProgress() { BroadcastByType("main", "cprogress", 0, "", nil) } -func PushReloadAttrView(avID string) { - BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": avID}) -} - func PushReloadDoc(rootID string) { BroadcastByType("main", "reloaddoc", 0, "", rootID) } From f18be1d0844b2345ceebbf5e4a036b3e4dee3626 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Thu, 5 Sep 2024 15:48:20 +0800 Subject: [PATCH 2/3] :art: Refresh the editor after rolling back the document https://github.com/siyuan-note/siyuan/issues/12397 --- kernel/model/history.go | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/model/history.go b/kernel/model/history.go index 95069cd23..539748567 100644 --- a/kernel/model/history.go +++ b/kernel/model/history.go @@ -284,6 +284,7 @@ func RollbackDocHistory(boxID, historyPath string) (err error) { sql.RemoveTreeQueue(id) sql.IndexTreeQueue(tree) util.PushReloadFiletree() + util.PushProtyleReload(id) util.PushMsg(Conf.Language(102), 3000) IncSync() From bea9641d288a0a3f6644f882d20de8b2ac95b59f Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Thu, 5 Sep 2024 15:48:55 +0800 Subject: [PATCH 3/3] :art: Improve rollback doc --- kernel/model/history.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/kernel/model/history.go b/kernel/model/history.go index 539748567..f2dd72478 100644 --- a/kernel/model/history.go +++ b/kernel/model/history.go @@ -288,6 +288,12 @@ func RollbackDocHistory(boxID, historyPath string) (err error) { util.PushMsg(Conf.Language(102), 3000) IncSync() + + // 刷新属性视图 + for _, avID := range avIDs { + ReloadAttrView(avID) + } + go func() { sql.WaitForWritingDatabase() @@ -310,11 +316,6 @@ func RollbackDocHistory(boxID, historyPath string) (err error) { "refText": refText, } util.PushEvent(evt) - - // 刷新属性视图 - for _, avID := range avIDs { - ReloadAttrView(avID) - } }() return nil }