Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config for start options cache #36

Merged
merged 8 commits into from
Mar 27, 2023
55 changes: 35 additions & 20 deletions gokey/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ import (
"time"
)

type THash string

// constans to select type of hash algorithm, Example:Options{Ahash:MD5}
var (
MD5 = THash("md5")
SHA256 = THash("sha256")
SHA1 = THash("sha1")
)

type Cache struct {
sync.RWMutex
pairsSet map[string]tuple //contains expiration time and value of a key

hashFn func([]byte) (string, error)
hashFn func([]byte) string
}

type tuple struct {
Expand All @@ -19,6 +28,14 @@ type tuple struct {
value []byte
}

// Options allow at user set properties of cache like
// maxsize or hash algorithm
type Options struct {
MaxSize int
AHast THash
TTL float64 // in Newcache or their methods?
}

var (
_ Operations = (*Cache)(nil)

Expand All @@ -27,11 +44,20 @@ var (
ErrExpiredKey = errors.New("key has expired")
)

func newCache() *Cache {
func newCache(o ...*Options) *Cache {
var options *Options

if len(o) < 1 || o[0] == nil {
options = &Options{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aca deberias poner una por defecto.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lo tomo en el proximo commit

} else {
options = o[0]
}

hashFn := selectHash(options.AHast)
return &Cache{
RWMutex: sync.RWMutex{},
pairsSet: make(map[string]tuple, getLimitPairsSet()),
hashFn: generateMD5,
pairsSet: make(map[string]tuple, sizeLimit(options.MaxSize)),
hashFn: hashFn,
}
}

Expand All @@ -44,10 +70,7 @@ func (c *Cache) Get(key string) ([]byte, error) {
c.RLock()
defer c.RUnlock()

keyHashed, err := c.hashFn([]byte(key))
if err != nil {
return nil, err
}
keyHashed := c.hashFn([]byte(key))

pair, exists := c.pairsSet[keyHashed]

Expand Down Expand Up @@ -83,10 +106,7 @@ func (c *Cache) Upsert(key string, value []byte, ttl time.Duration) (bool, error
c.Lock()
defer c.Unlock()

keyHashed, err := c.hashFn([]byte(key))
if err != nil {
return false, err
}
keyHashed := c.hashFn([]byte(key))

if c.pairsSet == nil {
c.pairsSet = make(map[string]tuple, getLimitPairsSet())
Expand All @@ -111,10 +131,8 @@ func (c *Cache) Delete(key string) (bool, error) {
c.Lock()
defer c.Unlock()

keyHashed, err := c.hashFn([]byte(key))
if err != nil {
return false, err
}
keyHashed := c.hashFn([]byte(key))

_, exists := c.pairsSet[keyHashed]

if exists {
Expand All @@ -134,10 +152,7 @@ func (c *Cache) Exists(key string) (bool, error) {
c.RLock()
defer c.RUnlock()

keyHashed, err := c.hashFn([]byte(key))
if err != nil {
return false, err
}
keyHashed := c.hashFn([]byte(key))

pair, exists := c.pairsSet[keyHashed]

Expand Down
2 changes: 1 addition & 1 deletion gokey/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"time"
)

var operations = newCache()
var operations = newCache(&Options{AHast: MD5})

// go test -run TestCacheUpsert -v
func TestCacheUpsert(t *testing.T) {
Expand Down
35 changes: 20 additions & 15 deletions gokey/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,33 @@ package gokey

import (
"crypto/md5"
"crypto/sha512"
"crypto/sha1"
"crypto/sha256"
"encoding/hex"
"hash"
)

// generateMD5 is a hash generator function according to input(key)
// using md5 algorithm.
func generateMD5(key []byte) (string, error) {
algorithm := md5.New()
_, err := algorithm.Write(key)
if err != nil {
return "", err

func selectHash(hash THash) func([]byte) string {
switch hash {
case "sha256":
return generateFromHash(sha256.New())
case "sha1":
return generateFromHash(sha1.New())
default:
return generateFromHash(md5.New())
}
return hex.EncodeToString(algorithm.Sum(nil)), nil
}

// generateSHA512
func generateSHA512(input string) (string, error) {
hasher := sha512.New()
_, err := hasher.Write([]byte(input))
if err != nil {
return "", err
func generateFromHash(algorithm hash.Hash) func([]byte) string {

return func(key []byte) string {
algorithm.Reset()
// write never return error
algorithm.Write(key)

return hex.EncodeToString(algorithm.Sum(nil))
}
hash := hasher.Sum(nil)
return hex.EncodeToString(hash), nil
}
42 changes: 39 additions & 3 deletions gokey/hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,59 @@ package gokey

import "testing"

type hashMD5Test struct {
type hashTest struct {
input []byte
output string
}

func TestGenerateMD5HashFromKey(t *testing.T) {
tests := []hashMD5Test{
tests := []hashTest{
{[]byte("foo"), "acbd18db4cc2f85cedef654fccc4a4d8"},
{[]byte("bar"), "37b51d194a7513e45b56f6524f2d51f2"},
{[]byte("gopher"), "ca654591d4ac97414391907f882b3c05"},
{[]byte("Irregardless"), "7dac0723ab11aec37ae53d26df848282"},
{[]byte("earthquake"), "e9ad9c2394f7dc7b6a69fb43e52a7382"},
{[]byte("endeavor"), "c5f5aaefa43684051f6fa380eef4b59e"},
}
generateMD5 := selectHash(MD5)
for _, v := range tests {
if out := generateMD5(v.input); out != v.output {
t.Errorf("Find %s, expected %s", string(v.output), out)
}
}

}

func TestGenerateSha1HashFromKey(t *testing.T) {
tests := []hashTest{
{[]byte("foo"), "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"},
{[]byte("bar"), "62cdb7020ff920e5aa642c3d4066950dd1f01f4d"},
{[]byte("gopher"), "4188736a00fbfb506aca06281acf338290455c21"},
{[]byte("Irregardless"), "bd633cd299f2b91082944cd661e21923f106bff2"},
{[]byte("earthquake"), "e8dea393aacba5f48ec3fdfd16114a89a2b59c63"},
{[]byte("endeavor"), "2c84ef5af854a4eefb5832ffc01d8c0edd261645"},
}
generateSha1 := selectHash(SHA1)
for _, v := range tests {
if out := generateSha1(v.input); out != v.output {
t.Errorf("Find %s, expected %s", string(v.output), out)
}
}

}

func TestGenerateSha256HashFromKey(t *testing.T) {
tests := []hashTest{
{[]byte("foo"), "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"},
{[]byte("bar"), "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"},
{[]byte("gopher"), "9cc1ee455a3363ffc504f40006f70d0c8276648a5d3eb3f9524e94d1b7a83aef"},
{[]byte("Irregardless"), "5bf4000a8a603e715286ad206e46a40e930c9e20998bf3ea36ddf687e6acced2"},
{[]byte("earthquake"), "fa7835fc1c74a9e014c750a4f452b56f215702a9802d386a0560e5099da94fbb"},
{[]byte("endeavor"), "1cd38b20bf937895efffc247bd9b85abbacfc5bfe21bfc12a44efa47a1da2343"},
}
generateSha256 := selectHash(SHA256)
for _, v := range tests {
if out, err := generateMD5(v.input); err != nil || out != v.output {
if out := generateSha256(v.input); out != v.output {
t.Errorf("Find %s, expected %s", string(v.output), out)
}
}
Expand Down
7 changes: 7 additions & 0 deletions gokey/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ package gokey
func isEmpty(key string) bool {
return key == ""
}

func sizeLimit(slimit int) int {
if slimit < 1 {
return getLimitPairsSet()
}
return slimit
}