MM-56876: Redis: first introduction (#27752)

```release-note
NONE
```

---------

Co-authored-by: Jesús Espino <jespinog@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Agniva De Sarker
2024-08-06 09:28:41 +05:30
коммит произвёл GitHub
родитель c3ed07e679
Коммит 540febd866
45 изменённых файлов: 1113 добавлений и 278 удалений

Просмотреть файл

@@ -17,7 +17,7 @@ import (
"github.com/mattermost/mattermost/server/v8/platform/shared/mail"
)
var latestVersionCache = cache.NewLRU(cache.LRUOptions{
var latestVersionCache = cache.NewLRU(&cache.CacheOptions{
Size: 1,
})

Просмотреть файл

@@ -12,7 +12,7 @@ import (
const LinkCacheSize = 10000
const LinkCacheDuration = 1 * time.Hour
var linkCache = cache.NewLRU(cache.LRUOptions{
var linkCache = cache.NewLRU(&cache.CacheOptions{
Size: LinkCacheSize,
})

Просмотреть файл

@@ -47,7 +47,7 @@ func StoreOverride(override any) Option {
func StoreOverrideWithCache(override store.Store) Option {
return func(ps *PlatformService) error {
ps.newStore = func() (store.Store, error) {
lcl, err := localcachelayer.NewLocalCacheLayer(override, ps.metricsIFace, ps.clusterIFace, ps.cacheProvider)
lcl, err := localcachelayer.NewLocalCacheLayer(override, ps.metricsIFace, ps.clusterIFace, ps.cacheProvider, ps.Log())
if err != nil {
return nil, err
}

Просмотреть файл

@@ -136,21 +136,6 @@ func New(sc ServiceConfig, options ...Option) (*PlatformService, error) {
// Assume the first user account has not been created yet. A call to the DB will later check if this is really the case.
ps.isFirstUserAccount.Store(true)
// Step 1: Cache provider.
// At the moment we only have this implementation
// in the future the cache provider will be built based on the loaded config
ps.cacheProvider = cache.NewProvider()
if err2 := ps.cacheProvider.Connect(); err2 != nil {
return nil, fmt.Errorf("unable to connect to cache provider: %w", err2)
}
// Apply options, some of the options overrides the default config actually.
for _, option := range options {
if err := option(ps); err != nil {
return nil, fmt.Errorf("failed to apply option: %w", err)
}
}
// the config store is not set, we need to create a new one
if ps.configStore == nil {
innerStore, err := config.NewFileStore("config.json", true)
@@ -166,13 +151,46 @@ func New(sc ServiceConfig, options ...Option) (*PlatformService, error) {
ps.configStore = configStore
}
// Step 2: Start logging.
if err := ps.initLogging(); err != nil {
return nil, fmt.Errorf("failed to initialize logging: %w", err)
// Step 1: Cache provider.
cacheConfig := ps.configStore.Get().CacheSettings
var err error
if *cacheConfig.CacheType == model.CacheTypeLRU {
ps.cacheProvider = cache.NewProvider()
} else if *cacheConfig.CacheType == model.CacheTypeRedis {
ps.cacheProvider, err = cache.NewRedisProvider(
&cache.RedisOptions{
RedisAddr: *cacheConfig.RedisAddress,
RedisPassword: *cacheConfig.RedisPassword,
RedisDB: *cacheConfig.RedisDB,
},
)
}
if err != nil {
return nil, fmt.Errorf("unable to create cache provider: %w", err)
}
// The value of res is used later, after the logger is initialized.
// There's a certain order of steps we need to follow in the server startup phase.
res, err := ps.cacheProvider.Connect()
if err != nil {
return nil, fmt.Errorf("unable to connect to cache provider: %w", err)
}
// Apply options, some of the options overrides the default config actually.
for _, option := range options {
if err2 := option(ps); err2 != nil {
return nil, fmt.Errorf("failed to apply option: %w", err2)
}
}
// Step 2: Start logging.
if err2 := ps.initLogging(); err2 != nil {
return nil, fmt.Errorf("failed to initialize logging: %w", err2)
}
ps.Log().Info("Successfully connected to cache backend", mlog.String("backend", *cacheConfig.CacheType), mlog.String("result", res))
// This is called after initLogging() to avoid a race condition.
mlog.Info("Server is initializing...", mlog.String("go_version", runtime.Version()))
ps.Log().Info("Server is initializing...", mlog.String("go_version", runtime.Version()))
// Step 3: Search Engine
searchEngine := searchengine.NewBroker(ps.Config())
@@ -192,6 +210,8 @@ func New(sc ServiceConfig, options ...Option) (*PlatformService, error) {
ps.metricsIFace = metricsInterfaceFn(ps, *ps.configStore.Get().SqlSettings.DriverName, *ps.configStore.Get().SqlSettings.DataSource)
}
ps.cacheProvider.SetMetrics(ps.metricsIFace)
// Step 6: Store.
// Depends on Step 0 (config), 1 (cacheProvider), 3 (search engine), 5 (metrics) and cluster.
if ps.newStore == nil {
@@ -206,7 +226,6 @@ func New(sc ServiceConfig, options ...Option) (*PlatformService, error) {
// Timer layer
// |
// Cache layer
var err error
ps.sqlStore, err = sqlstore.New(ps.Config().SqlSettings, ps.Log(), ps.metricsIFace)
if err != nil {
return nil, err
@@ -227,6 +246,7 @@ func New(sc ServiceConfig, options ...Option) (*PlatformService, error) {
ps.metricsIFace,
ps.clusterIFace,
ps.cacheProvider,
ps.Log(),
)
if err2 != nil {
return nil, fmt.Errorf("cannot create local cache layer: %w", err2)
@@ -267,14 +287,13 @@ func New(sc ServiceConfig, options ...Option) (*PlatformService, error) {
}
}
var err error
ps.Store, err = ps.newStore()
if err != nil {
return nil, fmt.Errorf("cannot create store: %w", err)
}
// Needed before loading license
ps.statusCache, err = ps.cacheProvider.NewCache(&cache.CacheOptions{
ps.statusCache, err = cache.NewProvider().NewCache(&cache.CacheOptions{
Name: "Status",
Size: model.StatusCacheSize,
Striped: true,
@@ -284,7 +303,8 @@ func New(sc ServiceConfig, options ...Option) (*PlatformService, error) {
return nil, fmt.Errorf("unable to create status cache: %w", err)
}
ps.sessionCache, err = ps.cacheProvider.NewCache(&cache.CacheOptions{
ps.sessionCache, err = cache.NewProvider().NewCache(&cache.CacheOptions{
Name: "Session",
Size: model.SessionCacheSize,
Striped: true,
StripedBuckets: maxInt(runtime.NumCPU()-1, 1),

Просмотреть файл

@@ -118,7 +118,7 @@ func (a *App) deduplicateCreatePost(rctx request.CTX, post *model.Post) (foundPo
}
if nErr != nil {
return nil, model.NewAppError("errorGetPostId", "api.post.error_get_post_id.pending", nil, "", http.StatusInternalServerError)
return nil, model.NewAppError("errorGetPostId", "api.post.error_get_post_id.pending", nil, "", http.StatusInternalServerError).Wrap(nErr)
}
// If another thread saved the cache record, but hasn't yet updated it with the actual post

Просмотреть файл

@@ -305,11 +305,13 @@ func NewServer(options ...Option) (*Server, error) {
model.AppErrorInit(i18n.T)
if s.seenPendingPostIdsCache, err = s.platform.CacheProvider().NewCache(&cache.CacheOptions{
Name: "seen_pending_post_ids",
Size: PendingPostIDsCacheSize,
}); err != nil {
return nil, errors.Wrap(err, "Unable to create pending post ids cache")
}
if s.openGraphDataCache, err = s.platform.CacheProvider().NewCache(&cache.CacheOptions{
Name: "opengraph_data",
Size: openGraphMetadataCacheSize,
}); err != nil {
return nil, errors.Wrap(err, "Unable to create opengraphdata cache")