diff --git a/kernel/api/transaction.go b/kernel/api/transaction.go index ff4a61f8e..fac594d81 100644 --- a/kernel/api/transaction.go +++ b/kernel/api/transaction.go @@ -94,5 +94,8 @@ func pushTransactions(app, session string, transactions []*model.Transaction) { evt.AppId = app evt.SessionId = session evt.Data = transactions + for _, tx := range transactions { + tx.WaitForCommit() + } util.PushEvent(evt) } diff --git a/kernel/av/table.go b/kernel/av/table.go index 1e2133bc7..985980322 100644 --- a/kernel/av/table.go +++ b/kernel/av/table.go @@ -28,10 +28,11 @@ type LayoutTable struct { Spec int `json:"spec"` // 布局格式版本 ID string `json:"id"` // 布局 ID - Columns []*ViewTableColumn `json:"columns"` // 表格列 - RowIDs []string `json:"rowIds"` // 行 ID,用于自定义排序 - Filters []*ViewFilter `json:"filters"` // 过滤规则 - Sorts []*ViewSort `json:"sorts"` // 排序规则 + Columns []*ViewTableColumn `json:"columns"` // 表格列 + RowIDs []string `json:"rowIds"` // 行 ID,用于自定义排序 + Filters []*ViewFilter `json:"filters"` // 过滤规则 + Sorts []*ViewSort `json:"sorts"` // 排序规则 + PageSize int `json:"pageSize"` // 每页行数 } type ViewTableColumn struct { @@ -571,13 +572,14 @@ func (value *Value) CompareOperator(other *Value, operator FilterOperator) bool // Table 描述了表格实例的结构。 type Table struct { - ID string `json:"id"` // 表格布局 ID - Icon string `json:"icon"` // 表格图标 - Name string `json:"name"` // 表格名称 - Filters []*ViewFilter `json:"filters"` // 过滤规则 - Sorts []*ViewSort `json:"sorts"` // 排序规则 - Columns []*TableColumn `json:"columns"` // 表格列 - Rows []*TableRow `json:"rows"` // 表格行 + ID string `json:"id"` // 表格布局 ID + Icon string `json:"icon"` // 表格图标 + Name string `json:"name"` // 表格名称 + Filters []*ViewFilter `json:"filters"` // 过滤规则 + Sorts []*ViewSort `json:"sorts"` // 排序规则 + Columns []*TableColumn `json:"columns"` // 表格列 + Rows []*TableRow `json:"rows"` // 表格行 + RowCount int `json:"rowCount"` // 表格总行数 } type TableColumn struct { diff --git a/kernel/go.mod b/kernel/go.mod index a66b5d8d6..ff098f38f 100644 --- a/kernel/go.mod +++ b/kernel/go.mod @@ -50,7 +50,7 @@ require ( github.com/rqlite/sql v0.0.0-20221103124402-8f9ff0ceb8f0 github.com/sashabaranov/go-openai v1.17.9 github.com/shirou/gopsutil/v3 v3.23.11 - github.com/siyuan-note/dejavu v0.0.0-20231208043525-6211184a4438 + github.com/siyuan-note/dejavu v0.0.0-20231208085113-c89895f2a075 github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75 github.com/siyuan-note/eventbus v0.0.0-20230804030110-cf250f838c80 github.com/siyuan-note/filelock v0.0.0-20231206081043-b75b363ddb1b diff --git a/kernel/go.sum b/kernel/go.sum index fbb4d6b0a..36b3a314f 100644 --- a/kernel/go.sum +++ b/kernel/go.sum @@ -356,8 +356,8 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d h1:lvCTyBbr36+tqMccdGMwuEU+hjux/zL6xSmf5S9ITaA= github.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8= -github.com/siyuan-note/dejavu v0.0.0-20231208043525-6211184a4438 h1:MMQYT1Kbrr2kgmwSwJXseCM+CUg5QmWMgFz3xseQIBk= -github.com/siyuan-note/dejavu v0.0.0-20231208043525-6211184a4438/go.mod h1:JFtbncCYIJft4Krp7U8wdxfqmV7DzpVpfBwz/KGUjX4= +github.com/siyuan-note/dejavu v0.0.0-20231208085113-c89895f2a075 h1:AS4npSJSgBXGMR09USiPgdXmeaIJ02p5xFmPZjMNSTs= +github.com/siyuan-note/dejavu v0.0.0-20231208085113-c89895f2a075/go.mod h1:JFtbncCYIJft4Krp7U8wdxfqmV7DzpVpfBwz/KGUjX4= github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75 h1:Bi7/7f29LW+Fm0cHc0J1NO1cZqyJwljSWVmfOqVZgaE= github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75/go.mod h1:H8fyqqAbp9XreANjeSbc72zEdFfKTXYN34tc1TjZwtw= github.com/siyuan-note/eventbus v0.0.0-20230804030110-cf250f838c80 h1:XghjHKJd+SiL0DkGYFVC+UGUDFtnR4v9gkAbPeh9Eq8= diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 4208946c4..f70bf8867 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -622,6 +622,8 @@ func renderAttributeViewTable(attrView *av.AttributeView, view *av.View, page, p return iv < jv }) + // 分页 + ret.RowCount = len(ret.Rows) if 0 < pageSize { start := (page - 1) * pageSize end := start + pageSize @@ -959,6 +961,34 @@ func setAttributeViewSorts(operation *Operation) (err error) { return } +func (tx *Transaction) doSetAttrViewPageSize(operation *Operation) (ret *TxErr) { + err := setAttributeViewPageSize(operation) + if nil != err { + return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()} + } + return +} + +func setAttributeViewPageSize(operation *Operation) (err error) { + attrView, err := av.ParseAttributeView(operation.AvID) + if nil != err { + return + } + + view, err := attrView.GetCurrentView() + if nil != err { + return + } + + switch view.LayoutType { + case av.LayoutTypeTable: + view.Table.PageSize = int(operation.Data.(float64)) + } + + err = av.SaveAttributeView(attrView) + return +} + func (tx *Transaction) doSetAttrViewColCalc(operation *Operation) (ret *TxErr) { err := setAttributeViewColumnCalc(operation) if nil != err { diff --git a/kernel/model/ocr.go b/kernel/model/ocr.go index f131716f9..75274a8d7 100644 --- a/kernel/model/ocr.go +++ b/kernel/model/ocr.go @@ -17,6 +17,8 @@ import ( ) func OCRAssetsJob() { + util.WaitForTesseractInit() + if !util.TesseractEnabled { return } @@ -25,6 +27,10 @@ func OCRAssetsJob() { } func autoOCRAssets() { + if !util.TesseractEnabled { + return + } + defer logging.Recover() assetsPath := util.GetDataAssetsAbsPath() @@ -38,7 +44,7 @@ func autoOCRAssets() { util.AssetsTexts[p] = text util.AssetsTextsLock.Unlock() if "" != text { - util.AssetsTextsChanged = true + util.AssetsTextsChanged.Store(true) } if 7 <= i { // 一次任务中最多处理 7 张图片,防止长时间占用系统资源 break @@ -65,7 +71,7 @@ func cleanNotExistAssetsTexts() { for _, asset := range toRemoves { delete(util.AssetsTexts, asset) - util.AssetsTextsChanged = true + util.AssetsTextsChanged.Store(true) } return } @@ -128,7 +134,7 @@ func LoadAssetsTexts() { } func SaveAssetsTexts() { - if !util.AssetsTextsChanged { + if !util.AssetsTextsChanged.Load() { return } @@ -154,5 +160,5 @@ func SaveAssetsTexts() { logging.LogWarnf("save assets texts [size=%s] to [%s], elapsed [%.2fs]", humanize.Bytes(uint64(len(data))), assetsTextsPath, elapsed) } - util.AssetsTextsChanged = false + util.AssetsTextsChanged.Store(false) } diff --git a/kernel/model/sync.go b/kernel/model/sync.go index 0b2601d3f..559821897 100644 --- a/kernel/model/sync.go +++ b/kernel/model/sync.go @@ -163,11 +163,11 @@ func SyncData(byHand bool) { func lockSync() { syncLock.Lock() - isSyncing = true + isSyncing.Store(true) } func unlockSync() { - isSyncing = false + isSyncing.Store(false) syncLock.Unlock() } @@ -178,15 +178,15 @@ func syncData(exit, byHand bool) { return } + lockSync() + defer unlockSync() + util.BroadcastByType("main", "syncing", 0, Conf.Language(81), nil) if !exit && !isProviderOnline(byHand) { // 这个操作比较耗时,所以要先推送 syncing 事件后再判断网络,这样才能给用户更即时的反馈 util.BroadcastByType("main", "syncing", 2, Conf.Language(28), nil) return } - lockSync() - defer unlockSync() - if exit { ExitSyncSucc = 0 logging.LogInfof("sync before exit") @@ -256,7 +256,7 @@ func checkSync(boot, exit, byHand bool) bool { } } - if isSyncing { + if isSyncing.Load() { logging.LogWarnf("sync is in progress") planSyncAfter(fixSyncInterval) return false @@ -431,7 +431,7 @@ func SetSyncProviderWebDAV(webdav *conf.WebDAV) (err error) { var ( syncLock = sync.Mutex{} - isSyncing bool + isSyncing = atomic.Bool{} ) func CreateCloudSyncDir(name string) (err error) { diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index a6efdf2a4..6bc09252d 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -23,6 +23,7 @@ import ( "path/filepath" "strings" "sync" + "sync/atomic" "time" "github.com/88250/gulu" @@ -128,6 +129,7 @@ func flushTx(tx *Transaction) { func PerformTransactions(transactions *[]*Transaction) { for _, tx := range *transactions { + tx.m = &sync.Mutex{} txQueue <- tx } return @@ -202,6 +204,8 @@ func performTx(tx *Transaction) (ret *TxErr) { ret = tx.doSetAttrViewFilters(op) case "setAttrViewSorts": ret = tx.doSetAttrViewSorts(op) + case "setAttrViewPageSize": + ret = tx.doSetAttrViewPageSize(op) case "setAttrViewColWidth": ret = tx.doSetAttrViewColumnWidth(op) case "setAttrViewColWrap": @@ -1168,8 +1172,6 @@ type Operation struct { Format string `json:"format"` // 属性视图列格式化 KeyID string `json:"keyID"` // 属性视列 ID RowID string `json:"rowID"` // 属性视图行 ID - - discard bool // 用于标识是否在事务合并中丢弃 } type Transaction struct { @@ -1181,6 +1183,18 @@ type Transaction struct { nodes map[string]*ast.Node luteEngine *lute.Lute + m *sync.Mutex + state atomic.Int32 // 0: 未提交,1: 已提交,2: 已回滚 +} + +func (tx *Transaction) WaitForCommit() { + for { + if 0 == tx.state.Load() { + time.Sleep(10 * time.Millisecond) + continue + } + return + } } func (tx *Transaction) begin() (err error) { @@ -1190,6 +1204,8 @@ func (tx *Transaction) begin() (err error) { tx.trees = map[string]*parse.Tree{} tx.nodes = map[string]*ast.Node{} tx.luteEngine = util.NewLute() + tx.m.Lock() + tx.state.Store(0) return } @@ -1202,11 +1218,15 @@ func (tx *Transaction) commit() (err error) { refreshDynamicRefTexts(tx.nodes, tx.trees) IncSync() tx.trees = nil + tx.state.Store(1) + tx.m.Unlock() return } func (tx *Transaction) rollback() { tx.trees, tx.nodes = nil, nil + tx.state.Store(2) + tx.m.Unlock() return } diff --git a/kernel/util/tesseract.go b/kernel/util/tesseract.go index 9f56c19c9..ace365b4b 100644 --- a/kernel/util/tesseract.go +++ b/kernel/util/tesseract.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" "github.com/88250/gulu" @@ -40,7 +41,7 @@ var ( TesseractMaxSize = 2 * 1000 * uint64(1000) AssetsTexts = map[string]string{} AssetsTextsLock = sync.Mutex{} - AssetsTextsChanged = false + AssetsTextsChanged = atomic.Bool{} TesseractLangs []string ) @@ -49,7 +50,7 @@ func SetAssetText(asset, text string) { AssetsTextsLock.Lock() AssetsTexts[asset] = text AssetsTextsLock.Unlock() - AssetsTextsChanged = true + AssetsTextsChanged.Store(true) } func ExistsAssetText(asset string) (ret bool) { @@ -75,7 +76,7 @@ func GetAssetText(asset string, force bool) (ret string) { AssetsTexts[asset] = ret AssetsTextsLock.Unlock() if "" != ret { - AssetsTextsChanged = true + AssetsTextsChanged.Store(true) } return } @@ -136,9 +137,21 @@ func Tesseract(imgAbsPath string) string { return ret } +var tesseractInited = atomic.Bool{} + +func WaitForTesseractInit() { + for { + if tesseractInited.Load() { + return + } + time.Sleep(time.Second) + } +} + func InitTesseract() { ver := getTesseractVer() if "" == ver { + tesseractInited.Store(true) return } @@ -146,6 +159,7 @@ func InitTesseract() { if 1 > len(langs) { logging.LogWarnf("no tesseract langs found") TesseractEnabled = false + tesseractInited.Store(true) return } @@ -162,6 +176,7 @@ func InitTesseract() { TesseractEnabled = enabledBool if !enabledBool { logging.LogInfof("tesseract-ocr disabled by env") + tesseractInited.Store(true) return } } @@ -169,6 +184,7 @@ func InitTesseract() { TesseractLangs = filterTesseractLangs(langs) logging.LogInfof("tesseract-ocr enabled [ver=%s, maxSize=%s, langs=%s]", ver, humanize.Bytes(TesseractMaxSize), strings.Join(TesseractLangs, "+")) + tesseractInited.Store(true) } func filterTesseractLangs(langs []string) (ret []string) {