@@ -84,7 +84,6 @@ local USER_SETTINGS_INFO = {}
8484local USER_SETTINGS_LIST = {}
8585local USER_SETTINGS_LOCATION_OVERRIDE = {}
8686local DATA_CACHE = {}
87- local DATA_CACHE_LEAF_FLAG = {}
8887local FLUSH_TIME = 0
8988local DATABASE_CONNECTION_ESTABLISHED = false
9089
@@ -139,6 +138,50 @@ local function DeleteInstanceInfoData(inst, info)
139138 end
140139end
141140
141+ -- 统一处理配置项存盘逻辑
142+ --- @param inst table 数据库实例
143+ --- @param info table 配置项信息
144+ --- @param szDataSetKey string | number DataSet 键值(可选,仅当配置项为 DataSet 类型时使用)
145+ --- @param xValue any 要保存的值
146+ --- @param bDelete boolean 是否为删除操作
147+ local function FlushSettingsData (inst , info , szDataSetKey , xValue , bDelete )
148+ if info .bDataSet then
149+ -- 处理 DataSet 类型的数据
150+ if bDelete then
151+ -- 删除 DataSet 中的某个键
152+ local res = GetInstanceInfoData (inst , info )
153+ if X .IsTable (res ) and res .v == info .szVersion and X .IsTable (res .d ) then
154+ res .d [szDataSetKey ] = nil
155+ if X .IsEmpty (res .d ) then
156+ DeleteInstanceInfoData (inst , info )
157+ else
158+ SetInstanceInfoData (inst , info , res .d , info .szVersion )
159+ end
160+ else
161+ DeleteInstanceInfoData (inst , info )
162+ end
163+ else
164+ -- 设置 DataSet 中的某个键
165+ local res = GetInstanceInfoData (inst , info )
166+ local dataToSave
167+ if X .IsTable (res ) and res .v == info .szVersion and X .IsTable (res .d ) then
168+ res .d [szDataSetKey ] = xValue
169+ dataToSave = res .d
170+ else
171+ dataToSave = { [szDataSetKey ] = xValue }
172+ end
173+ SetInstanceInfoData (inst , info , dataToSave , info .szVersion )
174+ end
175+ else
176+ -- 处理普通数据
177+ if bDelete then
178+ DeleteInstanceInfoData (inst , info )
179+ else
180+ SetInstanceInfoData (inst , info , xValue , info .szVersion )
181+ end
182+ end
183+ end
184+
142185function X .IsUserSettingsAvailable ()
143186 return DATABASE_CONNECTION_ESTABLISHED
144187end
@@ -230,6 +273,32 @@ function X.ReleaseUserSettingsDB()
230273end
231274
232275function X .FlushUserSettingsDB ()
276+ -- 遍历 DATA_CACHE 查找需要 flush 的数据
277+ for szKey , cache in pairs (DATA_CACHE ) do
278+ local info = USER_SETTINGS_INFO [szKey ]
279+ if info then
280+ local inst = DATABASE_INSTANCE [info .ePathType ]
281+ if inst then
282+ if cache .bDataSet then
283+ -- 处理 DataSet 类型的数据
284+ for szDataSetKey , dataSetCache in pairs (cache .tDataSet ) do
285+ if dataSetCache .bFlushRequired then
286+ FlushSettingsData (inst , info , szDataSetKey , dataSetCache .xValue , dataSetCache .bDeleted )
287+ -- 清除 flush 标记
288+ dataSetCache .bFlushRequired = nil
289+ end
290+ end
291+ else
292+ -- 处理普通数据
293+ if cache .bFlushRequired then
294+ FlushSettingsData (inst , info , nil , cache .xValue , cache .bDeleted )
295+ -- 清除 flush 标记
296+ cache .bFlushRequired = nil
297+ end
298+ end
299+ end
300+ end
301+ end
233302 -- for _, ePathType in ipairs(DATABASE_TYPE_LIST) do
234303 -- local inst = DATABASE_INSTANCE[ePathType]
235304 -- if inst then
350419-- {schema} tOption.xSchema 数据类型约束对象,通过 Schema 库生成
351420-- {boolean} tOption.bDataSet 是否为配置项组(如用户多套自定义偏好),配置项组在读写时需要额外传入一个组下配置项唯一键值(即多套自定义偏好中某一项的名字)
352421-- {table} tOption.tDataSetDefaultValue 数据默认值(仅当 bDataSet 为真时生效,用于设置配置项组不同默认值)
422+ -- {boolean} tOption.bPersistImmediatelyOnChange 是否在变更时立即持久化到文件,默认为 true,为 false 时变更会缓存在内存中等待系统空闲时写入
353423function X .RegisterUserSettings (szKey , tOption )
354- local ePathType , szDataKey , bUserData , bNoExport , szGroup , szLabel , szDescription , szVersion , szRestriction , xDefaultValue , xSchema , bDataSet , tDataSetDefaultValue , eDefaultLocationOverride
424+ local ePathType , szDataKey , bUserData , bNoExport , szGroup , szLabel , szDescription , szVersion , szRestriction , xDefaultValue , xSchema , bDataSet , tDataSetDefaultValue , eDefaultLocationOverride , bPersistImmediatelyOnChange
355425 if X .IsTable (tOption ) then
356426 ePathType = tOption .ePathType
357427 szDataKey = tOption .szDataKey
@@ -367,6 +437,7 @@ function X.RegisterUserSettings(szKey, tOption)
367437 bDataSet = tOption .bDataSet
368438 tDataSetDefaultValue = tOption .tDataSetDefaultValue
369439 eDefaultLocationOverride = tOption .eDefaultLocationOverride
440+ bPersistImmediatelyOnChange = tOption .bPersistImmediatelyOnChange
370441 end
371442 if not ePathType then
372443 ePathType = X .PATH_TYPE .ROLE
@@ -377,6 +448,9 @@ function X.RegisterUserSettings(szKey, tOption)
377448 if not szVersion then
378449 szVersion = ' '
379450 end
451+ if X .IsNil (bPersistImmediatelyOnChange ) then
452+ bPersistImmediatelyOnChange = true
453+ end
380454 if not X .IsString (szKey ) or szKey == ' ' then
381455 assert (false , ' RegisterUserSettings KEY(' .. X .EncodeLUAData (szKey ) .. ' ): `Key` should be a non-empty string value.' )
382456 end
@@ -442,6 +516,7 @@ function X.RegisterUserSettings(szKey, tOption)
442516 bDataSet = bDataSet ,
443517 tDataSetDefaultValue = tDataSetDefaultValue ,
444518 eDefaultLocationOverride = eDefaultLocationOverride ,
519+ bPersistImmediatelyOnChange = bPersistImmediatelyOnChange ,
445520 }
446521 setmetatable (tInfo , {
447522 __index = function (t , k )
@@ -505,30 +580,13 @@ end
505580-- @param {string} szDataSetKey 配置项组(如用户多套自定义偏好)唯一键,当且仅当 szKey 对应注册项携带 bDataSet 标记位时有效
506581-- @return 值
507582function X .GetUserSettings (szKey , ...)
508- -- 缓存加速
509- local cache = DATA_CACHE
510- for _ , k in ipairs ({szKey , ... }) do
511- if X .IsTable (cache ) then
512- cache = cache [k ]
513- end
514- if not X .IsTable (cache ) then
515- cache = nil
516- break
517- end
518- if cache [1 ] == DATA_CACHE_LEAF_FLAG then
519- return cache [2 ]
520- end
521- end
522583 -- 参数检查
523- local nParameter = select ( ' # ' , ... ) + 1
584+ local res , bData , bCache = nil , false , false
524585 local info = USER_SETTINGS_INFO [szKey ]
525586 if not info then
526587 assert (false , ' GetUserSettings KEY(' .. X .EncodeLUAData (szKey ) .. ' ): `Key` has not been registered.' )
527588 end
528- local inst = DATABASE_INSTANCE [info .ePathType ]
529- if not inst then
530- assert (false , ' GetUserSettings KEY(' .. X .EncodeLUAData (szKey ) .. ' ): Database not connected.' )
531- end
589+ local nParameter = select (' #' , ... ) + 1
532590 local szDataSetKey
533591 if info .bDataSet then
534592 if nParameter ~= 2 then
@@ -543,20 +601,44 @@ function X.GetUserSettings(szKey, ...)
543601 assert (false , ' GetUserSettings KEY(' .. X .EncodeLUAData (szKey ) .. ' ): 1 parameter expected, got ' .. nParameter )
544602 end
545603 end
546- -- 读数据库
547- local res , bData = GetInstanceInfoData (inst , info ), false
548- if X .IsTable (res ) and res .v == info .szVersion then
549- local data = res .d
550- if info .bDataSet then
551- if X .IsTable (data ) then
552- data = data [szDataSetKey ]
553- else
554- data = nil
604+ -- 缓存加速
605+ local cache = DATA_CACHE [szKey ]
606+ if info .bDataSet and ... then
607+ cache = X .IsTable (cache ) and cache .bDataSet
608+ and cache .tDataSet [... ]
609+ or nil
610+ end
611+ if X .IsTable (cache ) and cache .bValue then
612+ -- 从缓存获取数据,如果标记为删除则返回默认值
613+ if cache .bDeleted then
614+ -- 数据被删除但还没有 flush,直接返回默认值
615+ bData , bCache = false , true
616+ else
617+ res , bData , bCache = cache .xValue , true , true
618+ end
619+ end
620+ -- 未命中缓存,从数据库读取
621+ if not bCache then
622+ -- 参数检查
623+ local inst = DATABASE_INSTANCE [info .ePathType ]
624+ if not inst then
625+ assert (false , ' GetUserSettings KEY(' .. X .EncodeLUAData (szKey ) .. ' ): Database not connected.' )
626+ end
627+ -- 读数据库
628+ res , bData = GetInstanceInfoData (inst , info ), false
629+ if X .IsTable (res ) and res .v == info .szVersion then
630+ local data = res .d
631+ if info .bDataSet then
632+ if X .IsTable (data ) then
633+ data = data [szDataSetKey ]
634+ else
635+ data = nil
636+ end
637+ end
638+ if not info .xSchema or not X .Schema .CheckSchema (data , info .xSchema ) then
639+ bData = true
640+ res = data
555641 end
556- end
557- if not info .xSchema or not X .Schema .CheckSchema (data , info .xSchema ) then
558- bData = true
559- res = data
560642 end
561643 end
562644 -- 默认值
@@ -571,14 +653,26 @@ function X.GetUserSettings(szKey, ...)
571653 end
572654 res = X .Clone (res )
573655 end
574- -- 缓存
575- if info .bDataSet then
576- if not DATA_CACHE [szKey ] then
577- DATA_CACHE [szKey ] = {}
656+ -- 写入缓存
657+ if not bCache then
658+ if info .bDataSet then
659+ if not DATA_CACHE [szKey ] then
660+ DATA_CACHE [szKey ] = { bDataSet = true , tDataSet = {} }
661+ end
662+ DATA_CACHE [szKey ].tDataSet [szDataSetKey ] = {
663+ bValue = true ,
664+ xValue = res ,
665+ xRawValue = X .Clone (res ),
666+ bDeleted = false ,
667+ }
668+ else
669+ DATA_CACHE [szKey ] = {
670+ bValue = true ,
671+ xValue = res ,
672+ xRawValue = X .Clone (res ),
673+ bDeleted = false ,
674+ }
578675 end
579- DATA_CACHE [szKey ][szDataSetKey ] = { DATA_CACHE_LEAF_FLAG , res , X .Clone (res ) }
580- else
581- DATA_CACHE [szKey ] = { DATA_CACHE_LEAF_FLAG , res , X .Clone (res ) }
582676 end
583677 return res
584678end
@@ -612,14 +706,14 @@ function X.SetUserSettings(szKey, ...)
612706 if not X .IsString (szDataSetKey ) and not X .IsNumber (szDataSetKey ) then
613707 assert (false , ' SetUserSettings KEY(' .. X .EncodeLUAData (szKey ) .. ' ): `DataSetKey` should be a string or number value.' )
614708 end
615- cache = cache and cache [szDataSetKey ]
709+ cache = cache and cache . tDataSet [szDataSetKey ]
616710 else
617711 if nParameter ~= 2 then
618712 assert (false , ' SetUserSettings KEY(' .. X .EncodeLUAData (szKey ) .. ' ): 2 parameters expected, got ' .. nParameter )
619713 end
620714 xValue = ...
621715 end
622- if cache and cache [ 1 ] == DATA_CACHE_LEAF_FLAG and X .IsEquals (cache [ 3 ] , xValue ) then
716+ if cache and cache . bValue and X .IsEquals (cache . xRawValue , xValue ) then
623717 return
624718 end
625719 -- 数据校验
@@ -635,20 +729,33 @@ function X.SetUserSettings(szKey, ...)
635729 end
636730 -- 写数据库
637731 if info .bDataSet then
638- local res = GetInstanceInfoData (inst , info )
639- if X .IsTable (res ) and res .v == info .szVersion and X .IsTable (res .d ) then
640- res .d [szDataSetKey ] = xValue
641- xValue = res .d
642- else
643- xValue = { [szDataSetKey ] = xValue }
644- end
645- if X .IsTable (DATA_CACHE [szKey ]) then
646- DATA_CACHE [szKey ][szDataSetKey ] = nil
732+ -- 更新缓存
733+ if not DATA_CACHE [szKey ] then
734+ DATA_CACHE [szKey ] = { bDataSet = true , tDataSet = {} }
735+ end
736+ DATA_CACHE [szKey ].tDataSet [szDataSetKey ] = {
737+ bValue = true ,
738+ xValue = X .Clone (xValue ),
739+ xRawValue = X .Clone (xValue ),
740+ bFlushRequired = not info .bPersistImmediatelyOnChange ,
741+ bDeleted = false ,
742+ }
743+ if info .bPersistImmediatelyOnChange then
744+ FlushSettingsData (inst , info , szDataSetKey , xValue , false )
647745 end
648746 else
649- DATA_CACHE [szKey ] = nil
747+ -- 更新缓存
748+ DATA_CACHE [szKey ] = {
749+ bValue = true ,
750+ xValue = X .Clone (xValue ),
751+ xRawValue = X .Clone (xValue ),
752+ bFlushRequired = not info .bPersistImmediatelyOnChange ,
753+ bDeleted = false ,
754+ }
755+ if info .bPersistImmediatelyOnChange then
756+ FlushSettingsData (inst , info , nil , xValue , false )
757+ end
650758 end
651- SetInstanceInfoData (inst , info , xValue , info .szVersion )
652759 -- if info.bUserData then
653760 -- inst.bUserDataDBCommit = true
654761 -- else
@@ -705,24 +812,40 @@ function X.ResetUserSettings(szKey, ...)
705812 end
706813 -- 写数据库
707814 if info .bDataSet then
708- local res = GetInstanceInfoData (inst , info )
709- if X .IsTable (res ) and res .v == info .szVersion and X .IsTable (res .d ) and szDataSetKey then
710- res .d [szDataSetKey ] = nil
711- if X .IsEmpty (res .d ) then
712- DeleteInstanceInfoData (inst , info )
713- else
714- SetInstanceInfoData (inst , info , res .d , info .szVersion )
715- end
716- if DATA_CACHE [szKey ] then
717- DATA_CACHE [szKey ][szDataSetKey ] = nil
815+ -- 更新缓存
816+ if not DATA_CACHE [szKey ] then
817+ DATA_CACHE [szKey ] = { bDataSet = true , tDataSet = {} }
818+ end
819+ if szDataSetKey then
820+ DATA_CACHE [szKey ].tDataSet [szDataSetKey ] = {
821+ bValue = true ,
822+ xValue = nil ,
823+ xRawValue = nil ,
824+ bFlushRequired = not info .bPersistImmediatelyOnChange ,
825+ bDeleted = true ,
826+ }
827+ if info .bPersistImmediatelyOnChange then
828+ FlushSettingsData (inst , info , szDataSetKey , nil , true )
718829 end
719830 else
720- DeleteInstanceInfoData ( inst , info )
831+ -- 重置整个 DataSet
721832 DATA_CACHE [szKey ] = nil
833+ if info .bPersistImmediatelyOnChange then
834+ FlushSettingsData (inst , info , nil , nil , true )
835+ end
722836 end
723837 else
724- DeleteInstanceInfoData (inst , info )
725- DATA_CACHE [szKey ] = nil
838+ -- 更新缓存
839+ DATA_CACHE [szKey ] = {
840+ bValue = true ,
841+ xValue = nil ,
842+ xRawValue = nil ,
843+ bFlushRequired = not info .bPersistImmediatelyOnChange ,
844+ bDeleted = true ,
845+ }
846+ if info .bPersistImmediatelyOnChange then
847+ FlushSettingsData (inst , info , nil , nil , true )
848+ end
726849 end
727850 -- if info.bUserData then
728851 -- inst.bUserDataDBCommit = true
0 commit comments