-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
fix: improve cache synchronization mechanism #2312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,116 @@ | ||||||||||||||||||||||||||||||||
| package model | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||
| "testing" | ||||||||||||||||||||||||||||||||
| "time" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| "github.com/songquanpeng/one-api/common/config" | ||||||||||||||||||||||||||||||||
| "github.com/stretchr/testify/assert" | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // TestCacheSync tests the cache synchronization functionality | ||||||||||||||||||||||||||||||||
| func TestCacheSync(t *testing.T) { | ||||||||||||||||||||||||||||||||
| // Enable memory cache for testing | ||||||||||||||||||||||||||||||||
| config.MemoryCacheEnabled = true | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Initialize database connection for testing | ||||||||||||||||||||||||||||||||
| // Note: This assumes test database is configured | ||||||||||||||||||||||||||||||||
| InitDB() | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Test channel cache initialization | ||||||||||||||||||||||||||||||||
| t.Run("TestInitChannelCache", func(t *testing.T) { | ||||||||||||||||||||||||||||||||
| // Initialize cache | ||||||||||||||||||||||||||||||||
| InitChannelCache() | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Verify cache is built | ||||||||||||||||||||||||||||||||
| channelSyncLock.RLock() | ||||||||||||||||||||||||||||||||
| cacheExists := group2model2channels != nil | ||||||||||||||||||||||||||||||||
| channelSyncLock.RUnlock() | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| assert.True(t, cacheExists, "Channel cache should be initialized") | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Test cache invalidation | ||||||||||||||||||||||||||||||||
| t.Run("TestInvalidateChannelCache", func(t *testing.T) { | ||||||||||||||||||||||||||||||||
| // Initialize cache first | ||||||||||||||||||||||||||||||||
| InitChannelCache() | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Test cache invalidation | ||||||||||||||||||||||||||||||||
| InvalidateChannelCache(1) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Cache should be rebuilt after invalidation | ||||||||||||||||||||||||||||||||
| channelSyncLock.RLock() | ||||||||||||||||||||||||||||||||
| cacheExists := group2model2channels != nil | ||||||||||||||||||||||||||||||||
| channelSyncLock.RUnlock() | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| assert.True(t, cacheExists, "Cache should exist after invalidation") | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Test abilities-based cache building | ||||||||||||||||||||||||||||||||
| t.Run("TestBuildChannelCacheFromAbilities", func(t *testing.T) { | ||||||||||||||||||||||||||||||||
| // Create test channels | ||||||||||||||||||||||||||||||||
| channels := []*Channel{ | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| Id: 1, | ||||||||||||||||||||||||||||||||
| Status: ChannelStatusEnabled, | ||||||||||||||||||||||||||||||||
| Group: "default", | ||||||||||||||||||||||||||||||||
| Models: "gpt-3.5-turbo", | ||||||||||||||||||||||||||||||||
| Priority: &[]int64{0}[0], | ||||||||||||||||||||||||||||||||
|
Comment on lines
+52
to
+58
|
||||||||||||||||||||||||||||||||
| channels := []*Channel{ | |
| { | |
| Id: 1, | |
| Status: ChannelStatusEnabled, | |
| Group: "default", | |
| Models: "gpt-3.5-turbo", | |
| Priority: &[]int64{0}[0], | |
| priority := int64(0) | |
| channels := []*Channel{ | |
| { | |
| Id: 1, | |
| Status: ChannelStatusEnabled, | |
| Group: "default", | |
| Models: "gpt-3.5-turbo", | |
| Priority: &priority, |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ package model | |
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "strings" | ||
|
|
||
| "github.com/songquanpeng/one-api/common/config" | ||
| "github.com/songquanpeng/one-api/common/helper" | ||
|
|
@@ -136,13 +137,47 @@ func (channel *Channel) Insert() error { | |
|
|
||
| func (channel *Channel) Update() error { | ||
| var err error | ||
|
|
||
| // Get old channel info for cache invalidation | ||
| var oldChannel Channel | ||
| err = DB.Where("id = ?", channel.Id).First(&oldChannel).Error | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| err = DB.Model(channel).Updates(channel).Error | ||
| if err != nil { | ||
| return err | ||
| } | ||
| DB.Model(channel).First(channel, "id = ?", channel.Id) | ||
| err = channel.UpdateAbilities() | ||
| return err | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
Comment on lines
+154
to
+156
|
||
|
|
||
| // Invalidate caches if channel configuration changed | ||
| InvalidateChannelCache(channel.Id) | ||
|
|
||
| // Invalidate affected group caches | ||
| allGroups := make(map[string]bool) | ||
| // Add old groups | ||
| for _, group := range strings.Split(oldChannel.Group, ",") { | ||
| allGroups[strings.TrimSpace(group)] = true | ||
| } | ||
| // Add new groups | ||
| for _, group := range strings.Split(channel.Group, ",") { | ||
| allGroups[strings.TrimSpace(group)] = true | ||
| } | ||
|
|
||
| // Invalidate all affected groups | ||
| for group := range allGroups { | ||
| if group != "" { | ||
| InvalidateGroupModelCache(group) | ||
| } | ||
| } | ||
|
|
||
| logger.SysLog(fmt.Sprintf("updated channel #%d configuration and invalidated caches", channel.Id)) | ||
| return nil | ||
| } | ||
|
|
||
| func (channel *Channel) UpdateResponseTime(responseTime int64) { | ||
|
|
@@ -188,14 +223,41 @@ func (channel *Channel) LoadConfig() (ChannelConfig, error) { | |
| } | ||
|
|
||
| func UpdateChannelStatusById(id int, status int) { | ||
| err := UpdateAbilityStatus(id, status == ChannelStatusEnabled) | ||
| // Get channel info for cache invalidation | ||
| var channel Channel | ||
| err := DB.Where("id = ?", id).First(&channel).Error | ||
| if err != nil { | ||
| logger.SysError("failed to get channel info: " + err.Error()) | ||
| return | ||
| } | ||
|
|
||
| // Update abilities status | ||
| err = UpdateAbilityStatus(id, status == ChannelStatusEnabled) | ||
| if err != nil { | ||
| logger.SysError("failed to update ability status: " + err.Error()) | ||
| } | ||
|
|
||
| // Update channel status | ||
| err = DB.Model(&Channel{}).Where("id = ?", id).Update("status", status).Error | ||
| if err != nil { | ||
| logger.SysError("failed to update channel status: " + err.Error()) | ||
| return | ||
| } | ||
|
|
||
| // Immediately invalidate all related caches | ||
| InvalidateChannelCache(id) | ||
|
|
||
| // Invalidate affected group model caches | ||
| groups := strings.Split(channel.Group, ",") | ||
| for _, group := range groups { | ||
| InvalidateGroupModelCache(strings.TrimSpace(group)) | ||
| } | ||
|
|
||
| statusStr := "disabled" | ||
| if status == ChannelStatusEnabled { | ||
| statusStr = "enabled" | ||
| } | ||
| logger.SysLog(fmt.Sprintf("updated channel #%d status to %s and invalidated caches", id, statusStr)) | ||
| } | ||
|
|
||
| func UpdateChannelUsedQuota(id int, quota int64) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable
newChannelId2channelis created but never used in the updated InitChannelCache() function. This appears to be leftover code from the refactoring.