Skip to content

Commit

Permalink
no mutex as a struct field
Browse files Browse the repository at this point in the history
  • Loading branch information
parMaster committed Jun 19, 2024
1 parent ba8061c commit 00d1789
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 14 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ It will basically run a `Cleanup` method in a goroutine with a time interval.
100% test coverage:

```shell
$ go test -cover -race .
$ go test -cover -race -cpu 24 .

ok github.com/parMaster/mcache 8.239s coverage: 100.0% of statements
```
Expand Down
31 changes: 18 additions & 13 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ func (cacheItem CacheItem[T]) expired() bool {
// Cache is a struct for cache
type Cache[T any] struct {
data map[string]CacheItem[T]
mx sync.RWMutex
}

var mx sync.RWMutex

// Cacher is an interface for cache
type Cacher[T any] interface {
Set(key string, value T, ttl time.Duration) error
Expand Down Expand Up @@ -61,8 +62,8 @@ func NewCache[T any](options ...func(*Cache[T])) *Cache[T] {
// If key doesn't exist, set new value and return nil.
// If ttl is 0, set value without expiration
func (c *Cache[T]) Set(key string, value T, ttl time.Duration) error {
c.mx.Lock()
defer c.mx.Unlock()
mx.Lock()
defer mx.Unlock()
cached, ok := c.data[key]
if ok {
if !cached.expired() {
Expand Down Expand Up @@ -90,8 +91,8 @@ func (c *Cache[T]) Set(key string, value T, ttl time.Duration) error {
func (c *Cache[T]) Get(key string) (T, error) {
var none T

c.mx.Lock()
defer c.mx.Unlock()
mx.Lock()
defer mx.Unlock()

item, ok := c.data[key]
if !ok {
Expand All @@ -111,8 +112,8 @@ func (c *Cache[T]) Get(key string) (T, error) {
// If key exists, but it's expired, return false and delete key.
// If key exists and it's not expired, return true
func (c *Cache[T]) Has(key string) (bool, error) {
c.mx.Lock()
defer c.mx.Unlock()
mx.Lock()
defer mx.Unlock()

item, ok := c.data[key]
if !ok {
Expand All @@ -134,29 +135,33 @@ func (c *Cache[T]) Del(key string) error {
return err
}

c.mx.Lock()
// parallel goroutine can delete key right here
// or even perform Clear() operation
// but it doen't matter

mx.Lock()
delete(c.data, key)
c.mx.Unlock()
mx.Unlock()
return nil
}

// Clears cache by replacing it with a clean one
func (c *Cache[T]) Clear() error {
c.mx.Lock()
mx.Lock()
c.data = make(map[string]CacheItem[T])
c.mx.Unlock()
mx.Unlock()
return nil
}

// Cleanup deletes expired keys from cache
func (c *Cache[T]) Cleanup() {
c.mx.Lock()
mx.Lock()
for k, v := range c.data {
if v.expired() {
delete(c.data, k)
}
}
c.mx.Unlock()
mx.Unlock()
}

// WithCleanup is a functional option for setting interval to run Cleanup goroutine
Expand Down

0 comments on commit 00d1789

Please sign in to comment.