Skip to content

Commit

Permalink
[patch] exported Payload field (#11)
Browse files Browse the repository at this point in the history
[-] if Payload's fields are not exported, then implementing an external store would be impossible
as it cannot be serialized/deserialized with unexported fields.
  • Loading branch information
bnkamalesh authored Oct 28, 2024
1 parent cb89fad commit 5e73983
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 21 deletions.
22 changes: 13 additions & 9 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,22 @@ func (cfg *Config[K, T]) SanitizeValidate() error {
}

type Payload[T any] struct {
// cacheExpireAt is an atomic pointer to avoid race condition
// ExpireAt is an atomic pointer to avoid race condition
// while concurrently reading the timestamp
cacheExpireAt *atomic.Pointer[time.Time]
payload T
ExpireAt *atomic.Pointer[time.Time]
Payload T
}

func (pyl *Payload[T]) Expiry() time.Time {
return *pyl.cacheExpireAt.Load()
if pyl.ExpireAt == nil {
return time.Time{}
}

return *pyl.ExpireAt.Load()
}

func (pyl *Payload[T]) Value() T {
return pyl.payload
return pyl.Payload
}

type Tuple[K comparable, T any] struct {
Expand Down Expand Up @@ -232,7 +236,7 @@ func (ch *Cache[K, T]) Get(key K) Value[T] {
return v
}

expireAt := cp.cacheExpireAt.Load()
expireAt := cp.ExpireAt.Load()
delta := time.Since(*expireAt)
if delta >= 0 && ch.disableServeStale {
// cache expired and should be removed
Expand All @@ -246,7 +250,7 @@ func (ch *Cache[K, T]) Get(key K) Value[T] {
}

v.Found = true
v.V = cp.payload
v.V = cp.Payload

return v
}
Expand All @@ -261,8 +265,8 @@ func (ch *Cache[K, T]) Add(key K, value T) (evicted bool) {
cea.Store(&expireAt)

return ch.store.Add(key, &Payload[T]{
cacheExpireAt: &cea,
payload: value,
ExpireAt: &cea,
Payload: value,
})
}

Expand Down
55 changes: 43 additions & 12 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,16 +325,47 @@ func TestSanitize(tt *testing.T) {
func TestPayload(tt *testing.T) {
asserter := assert.New(tt)

expireAt := time.Now().Add(time.Minute)
cea := atomic.Pointer[time.Time]{}
cea.Store(&expireAt)
value := "hello world"

pyl := Payload[string]{
cacheExpireAt: &cea,
payload: value,
}

asserter.Equal(value, pyl.Value())
asserter.EqualValues(expireAt, pyl.Expiry())
tt.Run("expiry & payload available", func(t *testing.T) {
expireAt := time.Now().Add(time.Minute)
cea := atomic.Pointer[time.Time]{}
cea.Store(&expireAt)
value := "hello world"
pyl := Payload[string]{
ExpireAt: &cea,
Payload: value,
}
asserter.Equal(value, pyl.Value())
asserter.EqualValues(expireAt, pyl.Expiry())
})

tt.Run("expiry not available", func(t *testing.T) {
value := "hello world"
pyl := Payload[string]{
ExpireAt: nil,
Payload: value,
}
asserter.Equal(value, pyl.Value())
asserter.EqualValues(time.Time{}, pyl.Expiry())
})

tt.Run("value not available", func(t *testing.T) {
expireAt := time.Now().Add(time.Minute)
cea := atomic.Pointer[time.Time]{}
cea.Store(&expireAt)
pyl := Payload[any]{
ExpireAt: &cea,
Payload: nil,
}
asserter.Equal(nil, pyl.Value())
asserter.EqualValues(expireAt, pyl.Expiry())
})

tt.Run("expiry & value not available", func(t *testing.T) {
pyl := Payload[any]{
ExpireAt: nil,
Payload: nil,
}
asserter.Equal(nil, pyl.Value())
asserter.EqualValues(time.Time{}, pyl.Expiry())
})
}

0 comments on commit 5e73983

Please sign in to comment.