The introduction
- Following on from the previous article, this implementation uses Memcached as the storage source
- If you haven’t read the first two, please pay attention
- The first day
- The second day
- Using a third party driver library written by memcached author github.com/bradfitz/go…
- Case Code address
Define the Store structure
import (
"fmt"
"log"
"time"
"github.com/18211167516/gocache"
"github.com/bradfitz/gomemcache/memcache"
"github.com/gogf/gf/util/gconv"
)
type MemcachedStore struct {
MeClient *memcache.Client
SizeKey string // Calculate the number of key names
}
var MemCachedName = "Memcached"
Copy the code
2. Instantiate store and register cache
func NewMemcached(addr string) *MemcachedStore {
client := memcache.New(addr)
err := client.Ping()
iferr ! =nil {
log.Panic("Cache store Memcached:", err)
}
return &MemcachedStore{
MeClient: client,
SizeKey: "size",}}func RegisterMemcached(addr string) {
gocache.Register(MemCachedName, NewMemcached(addr))
}
Copy the code
3, the method of implementation
// The GC periodically scans to delete expired keys
func (ms *MemcachedStore) GC(a){}func (ms *MemcachedStore) GetStoreName(a) string {
return MemCachedName
}
func (ms *MemcachedStore) Get(key string) (interface{}, error) {
item, err := ms.MeClient.Get(key)
iferr ! =nil {
return nil, err
} else {
return gconv.String(item.Value), err
}
}
func NewMemItem(key string, value interface{}, d int) *memcache.Item {
return &memcache.Item{Key: key, Value: gconv.Bytes(value), Expiration: int32(10)}}func (ms *MemcachedStore) Incr(key string, i int) error {
if _, err := ms.MeClient.Increment(key, uint64(i)); err ! =nil {
if err == memcache.ErrCacheMiss {
return ms.Forever(key, gconv.String(i))
} else {
return err
}
}
return nil
}
func (ms *MemcachedStore) Decr(key string, i int) error {
if _, err := ms.MeClient.Decrement(key, uint64(i)); err ! =nil {
if err == memcache.ErrCacheMiss {
return ms.Forever(key, gconv.String(i))
} else {
return err
}
}
return nil
}
func (ms *MemcachedStore) Set(key string, value interface{}, d int) error {
item := NewMemItem(key, value, d)
iferr := ms.MeClient.Set(item); err ! =nil {
return err
} else {
return ms.Incr(ms.SizeKey, 1)}}func (ms *MemcachedStore) Delete(key string) error {
iferr := ms.MeClient.Delete(key); err ! =nil {
return err
} else {
return ms.Decr(ms.SizeKey, 1)}}func (ms *MemcachedStore) Has(key string) error {
item, err := ms.MeClient.Get(key)
iferr ! =nil {
return err
}
if item == nil {
return fmt.Errorf("Cache store Memcached key:%s not found", key)
}
return nil
}
func (ms *MemcachedStore) Forever(key string, value interface{}) error {
return ms.Set(key, value, 0)}func (ms *MemcachedStore) Clear(a) error {
return ms.MeClient.DeleteAll()
}
func (ms *MemcachedStore) Size(a) int {
value, err := ms.Get(ms.SizeKey)
iferr ! =nil {
return 0
} else {
return gconv.Int(value) - 1}}func (ms *MemcachedStore) GetTTl(key string) (time.Duration, error) {
iferr := ms.Has(key); err ! =nil {
return 0, err
} else {
item, _ := ms.MeClient.Get(key)
return time.Duration(item.Expiration), nil}}func (ms *MemcachedStore) IsExpire(key string) (bool, error) {
iferr := ms.Has(key); err ! =nil {
return false, err
} else {
item, _ := ms.MeClient.Get(key)
return item.Expiration > 0.nil}}Copy the code
4. Problems encountered
At first I thought it would be easy to use memcached, but in fact it was stuck in the Size method. Memcached does not provide a similar method. There is a stats info like Redis to get the system information
If you are careful, you should have noticed that I have added one more step to set and delete. At the same time, I will share with you why I wrote this way
func (ms *MemcachedStore) Incr(key string, i int) error {
if _, err := ms.MeClient.Increment(key, uint64(i)); err ! =nil { / / the first line
if err == memcache.ErrCacheMiss { / / the second line
return ms.Forever(key, gconv.String(i)) / / the third row
} else {
return err
}
}
return nil
}
Copy the code
- Memcached has a mechanism by which incrment increments and decrement returns a cache miss if the value does not exist
- In the second line we determine if the error is CachEmiss, which is similar to get
- In the third line, we permanently store the key that records size, and we also convert an int to a string. If we don’t do this, we’ll get an error
memcache: client error: cannot increment or decrement non-numeric value
5,Usage of the driver library
6, the end
This is the end of 3 days to build exclusive Cache, I hope you can have a little harvest, with progress
7. Series of articles
- Serial set up a Golang environment
- Serial 2 Install Gin
- Serial three defines the directory structure
- Serial four build case API1
- Serial five build case API2
- Serialized six access Swagger interface documents
- Serialize seven log components
- Serial eight graceful restart and stop
- Serialize the external Makefile build
- Serialize other Cron scheduled tasks
- Serialized content to create command-line tools
- 3 days to build exclusive Cache(First day)
- 3 days to build exclusive Cache(Second day)
- Third Day: Creating a dedicated Cache