-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Francesco Cosentino
committed
Jan 15, 2023
1 parent
f739134
commit 09e7005
Showing
2 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package models | ||
|
||
// Item represents an item in the cache. It has a key, value, expiration duration, and a last access time field. | ||
|
||
import ( | ||
"reflect" | ||
"strings" | ||
"sync" | ||
"sync/atomic" | ||
"time" | ||
|
||
// "https://github.com/kelindar/binary" | ||
"github.com/hyp3rd/hypercache/errors" | ||
"github.com/shamaton/msgpack/v2" | ||
) | ||
|
||
// Item is a struct that represents an item in the cache. It has a key, value, expiration duration, and a last access time field. | ||
type Item struct { | ||
Key string // key of the item | ||
Value any // Value of the item | ||
Expiration time.Duration // Expiration duration of the item | ||
LastAccess time.Time // LastAccess time of the item | ||
AccessCount uint // AccessCount of times the item has been accessed | ||
} | ||
|
||
// ItemPool is a pool of Item values. | ||
var ItemPool = sync.Pool{ | ||
New: func() any { | ||
return &Item{} | ||
}, | ||
} | ||
|
||
// FieldByName returns the value of the field of the Item struct with the given name. | ||
// If the field does not exist, an empty reflect.Value is returned. | ||
func (item *Item) FieldByName(name string) reflect.Value { | ||
// Get the reflect.Value of the item pointer | ||
v := reflect.ValueOf(item) | ||
|
||
// Get the reflect.Value of the item struct itself by calling Elem() on the pointer value | ||
f := v.Elem().FieldByName(name) | ||
|
||
// If the field does not exist, return an empty reflect.Value | ||
if !f.IsValid() { | ||
return reflect.Value{} | ||
} | ||
// Return the field value | ||
return f | ||
} | ||
|
||
// Valid returns an error if the item is invalid, nil otherwise. | ||
func (item *Item) Valid() error { | ||
// Check for empty key | ||
if item.Key == "" || strings.TrimSpace(item.Key) == "" { | ||
return errors.ErrInvalidKey | ||
} | ||
|
||
// Check for nil value | ||
if item.Value == nil { | ||
return errors.ErrNilValue | ||
} | ||
|
||
// Check for negative expiration | ||
if atomic.LoadInt64((*int64)(&item.Expiration)) < 0 { | ||
atomic.StoreInt64((*int64)(&item.Expiration), 0) | ||
return errors.ErrInvalidExpiration | ||
} | ||
return nil | ||
} | ||
|
||
// Touch updates the last access time of the item and increments the access count. | ||
func (item *Item) Touch() { | ||
item.LastAccess = time.Now() | ||
item.AccessCount++ | ||
} | ||
|
||
// Expired returns true if the item has expired, false otherwise. | ||
func (item *Item) Expired() bool { | ||
// If the expiration duration is 0, the item never expires | ||
return item.Expiration > 0 && time.Since(item.LastAccess) > item.Expiration | ||
} | ||
|
||
// MarshalBinary implements the encoding.BinaryMarshaler interface. | ||
// func (item *Item) MarshalBinary() (data []byte, err error) { | ||
// buf := bytes.NewBuffer([]byte{}) | ||
// enc := gob.NewEncoder(buf) | ||
// err = enc.Encode(item) | ||
// if err != nil { | ||
// return nil, err | ||
// } | ||
// return buf.Bytes(), nil | ||
// } | ||
|
||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. | ||
// | ||
// func (item *Item) UnmarshalBinary(data []byte) error { | ||
// buf := bytes.NewBuffer(data) | ||
// dec := gob.NewDecoder(buf) | ||
// return dec.Decode(item) | ||
// } | ||
// | ||
// MarshalBinary implements the encoding.BinaryMarshaler interface. | ||
func (item *Item) MarshalBinary() (data []byte, err error) { | ||
return msgpack.Marshal(item) | ||
} | ||
|
||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. | ||
func (item *Item) UnmarshalBinary(data []byte) error { | ||
return msgpack.Unmarshal(data, item) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package stats | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/hyp3rd/hypercache/errors" | ||
"github.com/hyp3rd/hypercache/types" | ||
) | ||
|
||
// Collector is an interface that defines the methods that a stats collector should implement. | ||
type Collector interface { | ||
// Incr increments the count of a statistic by the given value. | ||
Incr(stat types.Stat, value int64) | ||
// Decr decrements the count of a statistic by the given value. | ||
Decr(stat types.Stat, value int64) | ||
// Timing records the time it took for an event to occur. | ||
Timing(stat types.Stat, value int64) | ||
// Gauge records the current value of a statistic. | ||
Gauge(stat types.Stat, value int64) | ||
// Histogram records the statistical distribution of a set of values. | ||
Histogram(stat types.Stat, value int64) | ||
// GetStats returns the collected statistics. | ||
GetStats() Stats | ||
} | ||
|
||
// StatsCollectorRegistry holds the a registry of stats collectors. | ||
var StatsCollectorRegistry = make(map[string]func() (Collector, error)) | ||
|
||
// NewStatsCollector creates a new stats collector. | ||
// The statsCollectorName parameter is used to select the stats collector from the registry. | ||
func NewStatsCollector(statsCollectorName string) (Collector, error) { | ||
// Check the parameters. | ||
if statsCollectorName == "" { | ||
return nil, fmt.Errorf("%s: %s", errors.ErrParamCannotBeEmpty, "statsCollectorName") | ||
} | ||
|
||
createFunc, ok := StatsCollectorRegistry[statsCollectorName] | ||
if !ok { | ||
return nil, fmt.Errorf("%s: %s", errors.ErrStatsCollectorNotFound, statsCollectorName) | ||
} | ||
|
||
return createFunc() | ||
} | ||
|
||
// RegisterStatsCollector registers a new stats collector with the given name. | ||
func RegisterStatsCollector(name string, createFunc func() (Collector, error)) { | ||
StatsCollectorRegistry[name] = createFunc | ||
} | ||
|
||
func init() { | ||
// Register the default stats collector. | ||
RegisterStatsCollector("default", func() (Collector, error) { | ||
var err error | ||
collector := NewHistogramStatsCollector() | ||
if collector == nil { | ||
err = fmt.Errorf("%s: %s", errors.ErrStatsCollectorNotFound, "default") | ||
} | ||
return NewHistogramStatsCollector(), err | ||
}) | ||
} |