作者 yangfu

feat: table data cache v1

@@ -13,6 +13,7 @@ import ( @@ -13,6 +13,7 @@ import (
13 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log" 13 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
14 _ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log" 14 _ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
15 _ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/beego" 15 _ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/beego"
  16 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/event"
16 ) 17 )
17 18
18 const Version = "v1.2.0" 19 const Version = "v1.2.0"
@@ -34,7 +35,7 @@ func main() { @@ -34,7 +35,7 @@ func main() {
34 cron := crontab.NewCrontabService(nil) 35 cron := crontab.NewCrontabService(nil)
35 cron.StartCrontabTask() 36 cron.StartCrontabTask()
36 defer cron.StopCrontabTask() 37 defer cron.StopCrontabTask()
37 - 38 + event.Start()
38 log.Logger.Info("Service:" + constant.SERVICE_NAME) 39 log.Logger.Info("Service:" + constant.SERVICE_NAME)
39 log.Logger.Info("Version:" + Version) 40 log.Logger.Info("Version:" + Version)
40 log.Logger.Info("server start!") 41 log.Logger.Info("server start!")
@@ -2,16 +2,20 @@ package service @@ -2,16 +2,20 @@ package service
2 2
3 import ( 3 import (
4 "github.com/linmadan/egglib-go/core/application" 4 "github.com/linmadan/egglib-go/core/application"
  5 + pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
5 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/event/command" 6 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/event/command"
6 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/factory" 7 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/factory"
  8 + tablecommand "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/command"
  9 + tableservice "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/service"
7 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" 10 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
  11 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/cache"
  12 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/domainService"
8 ) 13 )
9 14
10 type TableEventService struct { 15 type TableEventService struct {
11 } 16 }
12 17
13 -func (tableEventService *TableEventService) Handler(ctx *domain.Context, createFileCommand *command.TableEventCommand) (interface{}, error) {  
14 - 18 +func (tableEventService *TableEventService) Handler(ctx *domain.Context, cmd *command.TableEventCommand) (interface{}, error) {
15 transactionContext, err := factory.CreateTransactionContext(nil) 19 transactionContext, err := factory.CreateTransactionContext(nil)
16 if err != nil { 20 if err != nil {
17 return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) 21 return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
@@ -23,10 +27,44 @@ func (tableEventService *TableEventService) Handler(ctx *domain.Context, createF @@ -23,10 +27,44 @@ func (tableEventService *TableEventService) Handler(ctx *domain.Context, createF
23 transactionContext.RollbackTransaction() 27 transactionContext.RollbackTransaction()
24 }() 28 }()
25 29
  30 + data := cmd.EventTable
  31 + tableId := 0
  32 + switch data.Type {
  33 + case domain.TableDataImportEvent, domain.TableDataEditEvent, domain.TableDeleteEvent:
  34 + tableId = data.Table.TableId
  35 + case domain.QuerySetUpdateEvent:
  36 + tableId = data.QuerySet.QuerySetInfo.BindTableId
  37 + }
  38 + if tableId == 0 {
  39 + return nil, nil
  40 + }
  41 + // tableId 相关联的
  42 + tableRepository, _, _ := factory.FastPgTable(transactionContext, 0)
  43 + _, tables, err := tableRepository.Find(map[string]interface{}{"context": data.Context, "tableTypesNotIn": []string{domain.TemporaryTable.ToString(), domain.ExcelTable.ToString()}})
  44 + if err != nil {
  45 + return nil, err
  46 + }
  47 +
  48 + tableDependencyService, _ := domainService.NewTableDependencyService(transactionContext.(*pgTransaction.TransactionContext))
  49 + tableDependTree := tableDependencyService.TableDependTree(tables, tableId)
  50 + tree := tableDependTree.Tree
  51 +
  52 + tableService := tableservice.NewTableService(nil)
  53 + for i := range tree {
  54 + cache.DefaultDataTableCacheService.DeleteDataTable(tree[i])
  55 + // fresh cache
  56 + tableService.TablePreview(data.Context, &tablecommand.TablePreviewCommand{
  57 + TableId: tree[i],
  58 + ObjectType: domain.ObjectMetaTable,
  59 + PageSize: 10000,
  60 + PageNumber: 0,
  61 + UseCache: true,
  62 + })
  63 + }
  64 +
26 if err := transactionContext.CommitTransaction(); err != nil { 65 if err := transactionContext.CommitTransaction(); err != nil {
27 return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) 66 return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
28 } 67 }
29 -  
30 return nil, nil 68 return nil, nil
31 } 69 }
32 70
@@ -72,6 +72,14 @@ func (tableService *TableService) TablePreview(ctx *domain.Context, cmd *command @@ -72,6 +72,14 @@ func (tableService *TableService) TablePreview(ctx *domain.Context, cmd *command
72 } 72 }
73 } 73 }
74 74
  75 + switch table.TableType {
  76 + case domain.CalculateSet.ToString():
  77 + response.Fields = dataTable.Fields
  78 + response.Data = domain.GripData(domain.ToFieldData(dataTable.Fields, dataTable.Data, false), int64(len(dataTable.Data)))
  79 + default:
  80 + response.Load(table, dataTable, domain.ObjectMetaTable)
  81 + }
  82 +
75 if cacheMiss && dataTable != nil { 83 if cacheMiss && dataTable != nil {
76 // 存储缓存 84 // 存储缓存
77 cache.SetDataTable(table.TableId, dataTable) 85 cache.SetDataTable(table.TableId, dataTable)
@@ -16,11 +16,22 @@ const ( @@ -16,11 +16,22 @@ const (
16 ) 16 )
17 17
18 type EventTable struct { 18 type EventTable struct {
  19 + Context *Context
19 Type EventType 20 Type EventType
20 Table *Table 21 Table *Table
21 QuerySet *QuerySet 22 QuerySet *QuerySet
22 } 23 }
23 24
  25 +func NewEventTable(ctx *Context, t EventType) *EventTable {
  26 + return &EventTable{
  27 + Context: ctx,
  28 + Type: t,
  29 + }
  30 +}
  31 +func (et *EventTable) WithContext(t *Context) *EventTable {
  32 + et.Context = t
  33 + return et
  34 +}
24 func (et *EventTable) WithType(t EventType) *EventTable { 35 func (et *EventTable) WithType(t EventType) *EventTable {
25 et.Type = t 36 et.Type = t
26 return et 37 return et
@@ -37,6 +48,7 @@ func (et *EventTable) WithQuerySet(t *QuerySet) *EventTable { @@ -37,6 +48,7 @@ func (et *EventTable) WithQuerySet(t *QuerySet) *EventTable {
37 } 48 }
38 49
39 func (et *EventTable) ResolveEvent(e event.Event) { 50 func (et *EventTable) ResolveEvent(e event.Event) {
  51 + et.Context = e.Get("Context").(*Context)
40 et.Type = e.Get("Type").(EventType) 52 et.Type = e.Get("Type").(EventType)
41 et.Table = e.Get("Table").(*Table) 53 et.Table = e.Get("Table").(*Table)
42 et.QuerySet = e.Get("QuerySet").(*QuerySet) 54 et.QuerySet = e.Get("QuerySet").(*QuerySet)
@@ -44,6 +56,7 @@ func (et *EventTable) ResolveEvent(e event.Event) { @@ -44,6 +56,7 @@ func (et *EventTable) ResolveEvent(e event.Event) {
44 56
45 func (et *EventTable) FireEvent() event.Event { 57 func (et *EventTable) FireEvent() event.Event {
46 e := event.M{} 58 e := event.M{}
  59 + e["Context"] = et.Context
47 e["Type"] = et.Type 60 e["Type"] = et.Type
48 e["Table"] = et.Table 61 e["Table"] = et.Table
49 e["QuerySet"] = et.QuerySet 62 e["QuerySet"] = et.QuerySet
@@ -4,6 +4,7 @@ import ( @@ -4,6 +4,7 @@ import (
4 "fmt" 4 "fmt"
5 cache "github.com/patrickmn/go-cache" 5 cache "github.com/patrickmn/go-cache"
6 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" 6 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
  7 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
7 "time" 8 "time"
8 ) 9 )
9 10
@@ -36,13 +37,17 @@ func (svr *DataTableCacheService) KeyDataTable(tableId int) string { @@ -36,13 +37,17 @@ func (svr *DataTableCacheService) KeyDataTable(tableId int) string {
36 func (svr *DataTableCacheService) GetDataTable(tableId int) (*domain.DataTable, bool) { 37 func (svr *DataTableCacheService) GetDataTable(tableId int) (*domain.DataTable, bool) {
37 v, ok := DefaultCache.Get(KeyDataTable(tableId)) 38 v, ok := DefaultCache.Get(KeyDataTable(tableId))
38 if !ok { 39 if !ok {
  40 + log.Logger.Info(fmt.Sprintf("【缓存】 miss cache %v", KeyDataTable(tableId)))
39 return nil, false 41 return nil, false
40 } 42 }
  43 + log.Logger.Info(fmt.Sprintf("【缓存】 hit cache %v", KeyDataTable(tableId)))
41 return v.(*domain.DataTable), true 44 return v.(*domain.DataTable), true
42 } 45 }
43 func (svr *DataTableCacheService) SetDataTable(tableId int, table *domain.DataTable) { 46 func (svr *DataTableCacheService) SetDataTable(tableId int, table *domain.DataTable) {
  47 + log.Logger.Info(fmt.Sprintf("【缓存】 set cache %v", KeyDataTable(tableId)))
44 DefaultCache.Set(KeyDataTable(tableId), table, 24*time.Hour*30) 48 DefaultCache.Set(KeyDataTable(tableId), table, 24*time.Hour*30)
45 } 49 }
46 func (svr *DataTableCacheService) DeleteDataTable(tableId int) { 50 func (svr *DataTableCacheService) DeleteDataTable(tableId int) {
  51 + log.Logger.Info(fmt.Sprintf("【缓存】 delete cache %v", KeyDataTable(tableId)))
47 DefaultCache.Delete(KeyDataTable(tableId)) 52 DefaultCache.Delete(KeyDataTable(tableId))
48 } 53 }
  1 +package domainService
  2 +
  3 +import (
  4 + "fmt"
  5 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
  6 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
  7 + "time"
  8 +)
  9 +
  10 +func AsyncEvent(e *domain.EventTable) {
  11 + go func() {
  12 + defer func() {
  13 + if p := recover(); p != nil {
  14 + log.Logger.Error(fmt.Sprintf("%v", p))
  15 + }
  16 + }()
  17 + time.Sleep(time.Second * 1)
  18 + e.FireEvent()
  19 + }()
  20 +}
@@ -95,6 +95,9 @@ func (ptr *QuerySetService) Update(ctx *domain.Context, querySetId int, queryCom @@ -95,6 +95,9 @@ func (ptr *QuerySetService) Update(ctx *domain.Context, querySetId int, queryCom
95 if err != nil { 95 if err != nil {
96 return err 96 return err
97 } 97 }
  98 + defer func() {
  99 + AsyncEvent(domain.NewEventTable(ctx, domain.QuerySetUpdateEvent).WithQuerySet(qs))
  100 + }()
98 if qs.Type == domain.SchemaTable.ToString() || qs.Type == domain.SubProcessTable.ToString() { 101 if qs.Type == domain.SchemaTable.ToString() || qs.Type == domain.SubProcessTable.ToString() {
99 return ptr.UpdateDefault(ctx, qs, queryComponents) 102 return ptr.UpdateDefault(ctx, qs, queryComponents)
100 } 103 }
@@ -409,6 +409,34 @@ func TestDataLayout(t *testing.T) { @@ -409,6 +409,34 @@ func TestDataLayout(t *testing.T) {
409 }, 409 },
410 flag: Location{X: 2, Y: 1}, 410 flag: Location{X: 2, Y: 1},
411 }, 411 },
  412 + {
  413 + title: "测试用例6",
  414 + cells: []*domain.LayoutCell{
  415 + // 分组一
  416 + {
  417 + X: 0,
  418 + Y: 0,
  419 + Length: 1,
  420 + ImageData: "a",
  421 + Direction: domain.DirectionNone,
  422 + },
  423 + {
  424 + X: 1,
  425 + Y: 1,
  426 + Length: 5,
  427 + ImageData: "c",
  428 + Direction: domain.DirectionRight,
  429 + },
  430 + {
  431 + X: 2,
  432 + Y: 1,
  433 + Length: 5,
  434 + ImageData: "d",
  435 + Direction: domain.DirectionRight,
  436 + },
  437 + },
  438 + flag: Location{X: 0, Y: 0},
  439 + },
412 } 440 }
413 padding := func(cells []*domain.LayoutCell) { 441 padding := func(cells []*domain.LayoutCell) {
414 for _, cell := range cells { 442 for _, cell := range cells {
@@ -472,7 +500,9 @@ b | | | | | | | | | @@ -472,7 +500,9 @@ b | | | | | | | | |
472 b | | | | | | | | | 500 b | | | | | | | | |
473 | | | | | d | d | d | d | d 501 | | | | | d | d | d | d | d
474 502
475 - 503 +a | | | | |
  504 + | c | c | c | c | c
  505 + | d | d | d | d | d
476 */ 506 */
477 507
478 func printRes(res *domain.DataTable) { 508 func printRes(res *domain.DataTable) {
@@ -24,7 +24,9 @@ func (ptr *AppendDataToTableService) AppendData(ctx *domain.Context, fileId int, @@ -24,7 +24,9 @@ func (ptr *AppendDataToTableService) AppendData(ctx *domain.Context, fileId int,
24 if err != nil { 24 if err != nil {
25 return nil, fmt.Errorf("表不存在") 25 return nil, fmt.Errorf("表不存在")
26 } 26 }
27 - 27 + defer func() {
  28 + AsyncEvent(domain.NewEventTable(ctx, domain.TableDataImportEvent).WithTable(table))
  29 + }()
28 excelTable, err := tableRepository.FindOne(map[string]interface{}{"tableId": file.FileInfo.TableId}) 30 excelTable, err := tableRepository.FindOne(map[string]interface{}{"tableId": file.FileInfo.TableId})
29 if err != nil { 31 if err != nil {
30 return nil, fmt.Errorf("文件未校验") 32 return nil, fmt.Errorf("文件未校验")
@@ -170,6 +170,9 @@ func (ptr *TableDependencyService) makeParentMap(tables []*domain.Table) map[int @@ -170,6 +170,9 @@ func (ptr *TableDependencyService) makeParentMap(tables []*domain.Table) map[int
170 if _, ok := res[tables[i].TableId]; !ok { 170 if _, ok := res[tables[i].TableId]; !ok {
171 res[tables[i].TableId] = make([]int, 0) 171 res[tables[i].TableId] = make([]int, 0)
172 } 172 }
  173 + if tables[i].TableInfo == nil {
  174 + continue
  175 + }
173 for _, t := range tables[i].TableInfo.DependencyTables { 176 for _, t := range tables[i].TableInfo.DependencyTables {
174 if _, ok := res[t]; !ok { 177 if _, ok := res[t]; !ok {
175 res[t] = make([]int, 0) 178 res[t] = make([]int, 0)
@@ -186,7 +189,9 @@ func (ptr *TableDependencyService) makeChildMap(tables []*domain.Table) map[int] @@ -186,7 +189,9 @@ func (ptr *TableDependencyService) makeChildMap(tables []*domain.Table) map[int]
186 if _, ok := res[id]; !ok { 189 if _, ok := res[id]; !ok {
187 res[id] = make([]int, 0) 190 res[id] = make([]int, 0)
188 } 191 }
189 - 192 + if tables[i].TableInfo == nil {
  193 + continue
  194 + }
190 res[id] = append(res[id], tables[i].TableInfo.DependencyTables...) 195 res[id] = append(res[id], tables[i].TableInfo.DependencyTables...)
191 } 196 }
192 return res 197 return res
@@ -250,7 +255,7 @@ func (ptr *TableDependencyService) makeTrees(childMap map[int][]int, rootNodes [ @@ -250,7 +255,7 @@ func (ptr *TableDependencyService) makeTrees(childMap map[int][]int, rootNodes [
250 255
251 func TableHasDependency(transactionContext *pgTransaction.TransactionContext, ctx *domain.Context, dependencyTable int) ([]*domain.Table, bool) { 256 func TableHasDependency(transactionContext *pgTransaction.TransactionContext, ctx *domain.Context, dependencyTable int) ([]*domain.Table, bool) {
252 tableRepository, _ := repository.NewTableRepository(transactionContext) 257 tableRepository, _ := repository.NewTableRepository(transactionContext)
253 - _, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "dependencyTable": dependencyTable}) 258 + _, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "dependencyTable": dependencyTable, "tableTypesNotIn": []string{domain.TemporaryTable.ToString()}})
254 if errors.Is(err, domain.ErrorNotFound) { 259 if errors.Is(err, domain.ErrorNotFound) {
255 return nil, false 260 return nil, false
256 } 261 }
@@ -37,6 +37,9 @@ func (ptr *TableEditDataService) RowEdit(ctx *domain.Context, request domain.Edi @@ -37,6 +37,9 @@ func (ptr *TableEditDataService) RowEdit(ctx *domain.Context, request domain.Edi
37 if table.TableType != domain.SideTable.ToString() { 37 if table.TableType != domain.SideTable.ToString() {
38 return nil, fmt.Errorf("副表才允许编辑数据") 38 return nil, fmt.Errorf("副表才允许编辑数据")
39 } 39 }
  40 + defer func() {
  41 + AsyncEvent(domain.NewEventTable(ctx, domain.TableDataEditEvent).WithTable(table))
  42 + }()
40 43
41 for _, l := range request.AddList { 44 for _, l := range request.AddList {
42 if addErr := ptr.add(ctx, table, l, request.Where); addErr != nil { 45 if addErr := ptr.add(ctx, table, l, request.Where); addErr != nil {
@@ -175,6 +175,9 @@ func (repository *TableRepository) Find(queryOptions map[string]interface{}) (in @@ -175,6 +175,9 @@ func (repository *TableRepository) Find(queryOptions map[string]interface{}) (in
175 if v, ok := queryOptions["tableTypes"]; ok && len(v.([]string)) > 0 { 175 if v, ok := queryOptions["tableTypes"]; ok && len(v.([]string)) > 0 {
176 query.Where(`table_type in (?)`, pg.In(v.([]string))) 176 query.Where(`table_type in (?)`, pg.In(v.([]string)))
177 } 177 }
  178 + if v, ok := queryOptions["tableTypesNotIn"]; ok && len(v.([]string)) > 0 {
  179 + query.Where(`table_type not in (?)`, pg.In(v.([]string)))
  180 + }
178 if v, ok := queryOptions["module"]; ok && v.(int) > 0 { 181 if v, ok := queryOptions["module"]; ok && v.(int) > 0 {
179 query.Where(`(cast(table_info->>'module' as integer) & ?) >0`, v) 182 query.Where(`(cast(table_info->>'module' as integer) & ?) >0`, v)
180 } 183 }
@@ -2,6 +2,7 @@ package event @@ -2,6 +2,7 @@ package event
2 2
3 import ( 3 import (
4 "github.com/gookit/event" 4 "github.com/gookit/event"
  5 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
5 ) 6 )
6 7
7 func Start() { 8 func Start() {
@@ -9,5 +10,8 @@ func Start() { @@ -9,5 +10,8 @@ func Start() {
9 } 10 }
10 11
11 func RegisterEvent() { 12 func RegisterEvent() {
12 - event.On("table.*", event.ListenerFunc(tableDataChangeHandler), event.High) 13 + event.On(domain.TableDataEditEvent.ToString(), event.ListenerFunc(tableDataChangeHandler), event.High)
  14 + event.On(domain.TableDataImportEvent.ToString(), event.ListenerFunc(tableDataChangeHandler), event.High)
  15 + event.On(domain.TableDeleteEvent.ToString(), event.ListenerFunc(tableDataChangeHandler), event.High)
  16 + event.On(domain.QuerySetUpdateEvent.ToString(), event.ListenerFunc(tableDataChangeHandler), event.High)
13 } 17 }