@@ -22,7 +22,9 @@ import (
22
22
"context"
23
23
"fmt"
24
24
"slices"
25
+ "time"
25
26
27
+ "github.com/ReneKroon/ttlcache/v2"
26
28
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
27
29
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
28
30
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
@@ -49,13 +51,19 @@ type Config struct {
49
51
DBHost string `mapstructure:"db_host"`
50
52
DBPort int `mapstructure:"db_port"`
51
53
DBName string `mapstructure:"db_name"`
54
+ // CacheTTL (seconds) determines how long the list of projects will be stored in a cache
55
+ // before a new database query is executed. The default, 0, corresponds to 60 seconds.
56
+ CacheTTL int `mapstructure:"cache_ttl"`
52
57
}
53
58
54
59
type mgr struct {
55
- c * Config
56
- db * gorm.DB
60
+ c * Config
61
+ db * gorm.DB
62
+ cache * ttlcache.Cache
57
63
}
58
64
65
+ const cacheKey = "projects/projectsListCache"
66
+
59
67
// Project represents a project in the DB.
60
68
type Project struct {
61
69
gorm.Model
@@ -96,26 +104,37 @@ func New(ctx context.Context, m map[string]any) (projects.Catalogue, error) {
96
104
return nil , errors .Wrap (err , "Failed to mgirate Project schema" )
97
105
}
98
106
107
+ cache := ttlcache .NewCache ()
108
+ if c .CacheTTL == 0 {
109
+ c .CacheTTL = 60
110
+ }
111
+ cache .SetTTL (time .Duration (c .CacheTTL ))
112
+ // Even if we get a hit, of course we just want to refresh every 60 seconds
113
+ cache .SkipTTLExtensionOnHit (true )
99
114
mgr := & mgr {
100
- c : & c ,
101
- db : db ,
115
+ c : & c ,
116
+ db : db ,
117
+ cache : cache ,
102
118
}
103
119
return mgr , nil
104
120
}
105
121
106
122
func (m * mgr ) ListProjects (ctx context.Context , user * userpb.User ) ([]* provider.StorageSpace , error ) {
107
- // TODO: we reallyyy should not be loading everything into memory here...
108
-
109
- var dbProjects []* Project
110
-
111
- query := m .db .Model (& Project {})
112
- res := query .Find (& dbProjects )
113
- if res .Error != nil {
114
- return nil , res .Error
123
+ var fetchedProjects []* Project
124
+
125
+ if res , err := m .cache .Get (cacheKey ); err == nil && res != nil {
126
+ fetchedProjects = res .([]* Project )
127
+ } else {
128
+ query := m .db .Model (& Project {})
129
+ res := query .Find (& fetchedProjects )
130
+ if res .Error != nil {
131
+ return nil , res .Error
132
+ }
133
+ m .cache .Set (cacheKey , fetchedProjects )
115
134
}
116
135
117
136
projects := []* provider.StorageSpace {}
118
- for _ , p := range dbProjects {
137
+ for _ , p := range fetchedProjects {
119
138
if perms , ok := projectBelongToUser (user , p ); ok {
120
139
projects = append (projects , & provider.StorageSpace {
121
140
Id : & provider.StorageSpaceId {
0 commit comments