Skip to content

Commit 182d3aa

Browse files
committed
feat(storers): Use UUID for memcached keys
1 parent 95cace4 commit 182d3aa

File tree

1 file changed

+72
-46
lines changed

1 file changed

+72
-46
lines changed

pkg/storage/nutsMemcachedProvider.go

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
t "github.com/darkweak/souin/configurationtypes"
1313
"github.com/darkweak/souin/pkg/rfc"
1414
"github.com/darkweak/souin/pkg/storage/types"
15+
"github.com/google/uuid"
1516
"github.com/imdario/mergo"
1617
"github.com/nutsdb/nutsdb"
1718
"go.uber.org/zap"
@@ -179,29 +180,10 @@ func (provider *NutsMemcached) MapKeys(prefix string) map[string]string {
179180

180181
// Get method returns the populated response if exists, empty response then
181182
func (provider *NutsMemcached) Get(key string) (item []byte) {
182-
// get from nuts
183-
keyFound := false
184-
{
185-
_ = provider.DB.View(func(tx *nutsdb.Tx) error {
186-
i, e := tx.Get(bucket, []byte(key))
187-
if i != nil {
188-
// Value is stored in memcached
189-
//item = i.Value
190-
keyFound = true
191-
}
192-
return e
193-
})
194-
}
195-
196-
// get from memcached
197-
if keyFound {
198-
// Reminder: the key must be at most 250 bytes in length
199-
//fmt.Println("memcached GET", key)
200-
i, e := provider.memcacheClient.Get(key)
201-
if e == nil && i != nil {
202-
item = i.Value
203-
}
183+
memcachedKey, _ := provider.getFromNuts(key)
204184

185+
if memcachedKey != "" {
186+
item, _ = provider.getFromMemcached(memcachedKey)
205187
}
206188

207189
return
@@ -220,14 +202,14 @@ func (provider *NutsMemcached) Prefix(key string, req *http.Request, validator *
220202
for _, entry := range entries {
221203
if varyVoter(key, req, string(entry.Key)) {
222204
// TODO: improve this
223-
// store header only in nuts and avoid query to memcached on each vary
205+
// Store only response header in nuts and avoid query to memcached on each vary
224206
// E.g, rfc.ValidateETag on NutsDB header value, retrieve response body later from memcached.
225207

226208
// Reminder: the key must be at most 250 bytes in length
227209
//fmt.Println("memcached PREFIX", key, "GET", string(entry.Key))
228-
i, e := provider.memcacheClient.Get(string(entry.Key))
229-
if e == nil && i != nil {
230-
res, err := http.ReadResponse(bufio.NewReader(bytes.NewBuffer(i.Value)), req)
210+
i, e := provider.getFromMemcached(string(entry.Value))
211+
if e == nil {
212+
res, err := http.ReadResponse(bufio.NewReader(bytes.NewBuffer(i)), req)
231213
if err == nil {
232214
rfc.ValidateETag(res, validator)
233215
if validator.Matched {
@@ -257,12 +239,14 @@ func (provider *NutsMemcached) Set(key string, value []byte, url t.URL, ttl time
257239
if ttl == 0 {
258240
ttl = url.TTL.Duration
259241
}
242+
memcachedKey := uuid.New().String()
260243

261244
// set to nuts (normal TTL)
262245
{
263246
err := provider.DB.Update(func(tx *nutsdb.Tx) error {
264-
// No value is stored, value is stored in memcached
265-
return tx.Put(bucket, []byte(key), []byte{}, uint32(ttl.Seconds()))
247+
248+
// key: cache-key, value: memcached-key
249+
return tx.Put(bucket, []byte(key), []byte(memcachedKey), uint32(ttl.Seconds()))
266250
})
267251

268252
if err != nil {
@@ -275,8 +259,8 @@ func (provider *NutsMemcached) Set(key string, value []byte, url t.URL, ttl time
275259
staleTtl := int32((provider.stale + ttl).Seconds())
276260
{
277261
err := provider.DB.Update(func(tx *nutsdb.Tx) error {
278-
// No value is stored, value is stored in memcached
279-
return tx.Put(bucket, []byte(StalePrefix+key), []byte{}, uint32(staleTtl))
262+
// key: "STALE_" + cache-key, value: memcached-key
263+
return tx.Put(bucket, []byte(StalePrefix+key), []byte(memcachedKey), uint32(staleTtl))
280264
})
281265

282266
if err != nil {
@@ -285,38 +269,36 @@ func (provider *NutsMemcached) Set(key string, value []byte, url t.URL, ttl time
285269
}
286270

287271
// set to memcached with stale TTL
288-
{
289-
// Reminder: the key must be at most 250 bytes in length
290-
//fmt.Println("memcached SET", key)
291-
err := provider.memcacheClient.Set(
292-
&memcache.Item{
293-
Key: key,
294-
Value: value,
295-
Expiration: staleTtl,
296-
},
297-
)
298-
if err != nil {
299-
provider.logger.Sugar().Errorf("Impossible to set value into Memcached, %v", err)
300-
}
301-
}
272+
_ = provider.setToMemcached(memcachedKey, value, staleTtl)
302273

303274
return nil
304275
}
305276

306277
// Delete method will delete the response in Nuts provider if exists corresponding to key param
307278
func (provider *NutsMemcached) Delete(key string) {
279+
memcachedKey, _ := provider.getFromNuts(key)
280+
281+
// delete from memcached
282+
if memcachedKey != "" {
283+
_ = provider.delFromMemcached(memcachedKey)
284+
}
285+
286+
// delete from nuts
308287
_ = provider.DB.Update(func(tx *nutsdb.Tx) error {
309288
return tx.Delete(bucket, []byte(key))
310289
})
311290
}
312291

313292
// DeleteMany method will delete the responses in Nuts provider if exists corresponding to the regex key param
314-
func (provider *NutsMemcached) DeleteMany(key string) {
293+
func (provider *NutsMemcached) DeleteMany(keyReg string) {
315294
_ = provider.DB.Update(func(tx *nutsdb.Tx) error {
316-
if entries, err := tx.PrefixSearchScan(bucket, []byte(""), key, 0, nutsLimit); err != nil {
295+
if entries, err := tx.PrefixSearchScan(bucket, []byte(""), keyReg, 0, nutsLimit); err != nil {
317296
return err
318297
} else {
319298
for _, entry := range entries {
299+
// delete from memcached
300+
_ = provider.delFromMemcached(string(entry.Value))
301+
// delete from nuts
320302
_ = tx.Delete(bucket, entry.Key)
321303
}
322304
}
@@ -335,3 +317,47 @@ func (provider *NutsMemcached) Reset() error {
335317
return tx.DeleteBucket(1, bucket)
336318
})
337319
}
320+
321+
func (provider *NutsMemcached) getFromNuts(nutsKey string) (memcachedKey string, err error) {
322+
err = provider.DB.View(func(tx *nutsdb.Tx) error {
323+
i, e := tx.Get(bucket, []byte(nutsKey))
324+
if i != nil {
325+
memcachedKey = string(i.Value)
326+
}
327+
return e
328+
})
329+
return
330+
}
331+
332+
// Reminder: the memcachedKey must be at most 250 bytes in length
333+
func (provider *NutsMemcached) setToMemcached(memcachedKey string, value []byte, ttl int32) (err error) {
334+
//fmt.Println("memcached SET", key)
335+
err = provider.memcacheClient.Set(
336+
&memcache.Item{
337+
Key: memcachedKey,
338+
Value: value,
339+
Expiration: ttl,
340+
},
341+
)
342+
if err != nil {
343+
provider.logger.Sugar().Errorf("Failed to set into memcached, %v", err)
344+
}
345+
return
346+
}
347+
348+
// Reminder: the memcachedKey must be at most 250 bytes in length
349+
func (provider *NutsMemcached) getFromMemcached(memcachedKey string) (value []byte, err error) {
350+
//fmt.Println("memcached GET", key)
351+
i, err := provider.memcacheClient.Get(memcachedKey)
352+
if err == nil && i != nil {
353+
value = i.Value
354+
} else {
355+
provider.logger.Sugar().Errorf("Failed to get from memcached, %v", err)
356+
}
357+
return
358+
}
359+
360+
func (provider *NutsMemcached) delFromMemcached(memcachedKey string) (err error) {
361+
err = provider.memcacheClient.Delete(memcachedKey)
362+
return
363+
}

0 commit comments

Comments
 (0)