项目结构:
├── README.md
├── cache
│ ├── cache.go
│ ├── cache_store.go
│ ├── iCache.go
│ ├── mcache.go
│ └── mcache_test.go
├── cache_server
│ ├── cacheServer.go
│ └── cacheServer_test.go
├── constant
│ └── constant.go
├── cuserror
│ └── error.go
├── go.mod
├── logger
│ ├── console.go
│ ├── file.go
│ ├── file_test.go
│ ├── iLogger.go
│ ├── logger.go
│ └── logger_test.go
├── main.go
└── util
├── util.go
└── util_test.go
6 directories, 20 files
package cache
import "time"
type ICache interface {
SetMaxMemory(size string) bool
Set(key string, val interface{}, expire time.Duration)
Get(key string) (interface{}, bool)
Del(key string) bool
Exists(key string) bool
Flush() bool
Keys() int64
ClearExpireNode()
}
package cache
import (
"fmt"
"time"
)
type mNode struct{
Key string
Value interface{}
InsertTime time.Time
Expire time.Duration
Next *mNode
}
type linkedList struct {
firstNode *mNode
}
func NewLinkedList() *linkedList{
return &linkedList{}
}
func (link *linkedList) isEmpty() bool {
if link.firstNode == nil {
return true
}
return false
}
func (link *linkedList) Size() int64{
first := link.firstNode
var count int64 = 0
for first != nil {
count++
first = first.Next
}
return count
}
func (link *linkedList)Add(key string,value interface{},expire time.Duration) bool{
node := &mNode{
Key:key,
Value: value,
Expire:expire,
InsertTime:time.Now(),
}
node.Next = link.firstNode
link.firstNode = node
return true
}
func (link *linkedList) Append(key string,value interface{},expire time.Duration) bool{
newNode := &mNode{
Key:key,
Value:value,
Expire:expire,
InsertTime:time.Now(),
}
node := link.firstNode
if node == nil {
link.firstNode = newNode
return true
}else {
for node.Next != nil {
node = node.Next
}
node.Next = newNode
return true
}
return false
}
func (link *linkedList)Insert(index int64,key string,value interface{},expire time.Duration) bool {
newMode := &mNode{
Key:key,
Value:value,
Expire:expire,
}
node := link.firstNode
if index < 0 {
link.Add(key,value,expire)
return true
} else if index > link.Size(){
link.Append(key,value,expire)
return true
}else {
var count int64 = 0
for count < (index -1 ){
node = node.Next
count +=1
}
newMode.Next = node.Next
node.Next = newMode
return true
}
return false
}
func (link *linkedList) Delete(key interface{}) bool {
node := link.firstNode
if node != nil && node.Key == key {
link.firstNode = node.Next
}else{
for node != nil && node.Next != nil {
if node.Next.Key == key{
node.Next = node.Next.Next
return true
}else{
node = node.Next
}
}
}
return false
}
func (link *linkedList) forEachLink() {
node := link.firstNode
for node != nil {
str := fmt.Sprintf("{\"%v\":%v}",node.Key,node.Value)
fmt.Printf("%v\n",str)
node = node.Next
}
}
func (link *linkedList) Get(key string) *mNode {
node := link.firstNode
for node != nil {
if node.Key == key {
return node
}
node = node.Next
}
return nil
}
func (link *linkedList) IsExists(key string) bool {
node := link.firstNode
for node != nil {
if node.Key == key {
return true
}
node = node.Next
}
return false
}
func (link *linkedList) isExpire(key string) (string,bool) {
node := link.firstNode
for node != nil {
if node.Key == key {
return key,time.Now().Sub(node.InsertTime) > node.Expire
}
node = node.Next
}
return key,false
}
func (link *linkedList) Empty() bool{
node := link.firstNode
for node != nil {
link.Delete(node.Key)
node = node.Next
}
return true
}
func (link *linkedList) GetExpireKeys() (keys []string ) {
node := link.firstNode
for node != nil {
if time.Now().Sub(node.InsertTime) > node.Expire {
keys = append(keys,node.Key)
}
node = node.Next
}
return
}
package cache
import (
"cache-system/logger"
"cache-system/util"
"sync"
"time"
)
type Cache struct {
SizeStr string
size int64
cookieMap *linkedList
rwLock sync.RWMutex
Interval int
}
func NewCache(size string,interval int) ICache{
return &Cache{
SizeStr: size,
size: util.ParseSize(size),
cookieMap: NewLinkedList(),
Interval:interval,
}
}
func (c *Cache)SetMaxMemory(size string) bool {
c.rwLock.RLock()
defer c.rwLock.Unlock()
c.SizeStr = size
c.size = util.ParseSize(size)
return true
}
func (c *Cache)Set(key string, val interface{}, expire time.Duration) {
c.rwLock.Lock()
defer c.rwLock.Unlock()
if c.Exists(key){
c.cookieMap.Delete(key)
}
c.cookieMap.Add(key,val,expire)
}
func (c *Cache)Get(key string) (interface{}, bool){
c.rwLock.RLock()
defer c.rwLock.RUnlock()
var t bool = false
cache := c.cookieMap.Get(key)
if cache != nil {
t = true
}
if cache != nil {
return cache.Value,t
}
return nil,false
}
func (c *Cache)Del(key string) bool{
c.rwLock.Lock()
defer c.rwLock.Unlock()
return c.cookieMap.Delete(key)
}
func (c *Cache)Exists(key string) bool{
return c.cookieMap.IsExists(key)
}
func (c *Cache)Flush() bool{
c.rwLock.Lock()
defer c.rwLock.Unlock()
return c.cookieMap.Empty()
}
func (c *Cache)Keys() int64{
c.rwLock.Lock()
defer c.rwLock.Unlock()
return c.cookieMap.Size()
}
func (c *Cache) ClearExpireNode(){
for{
logger.Info("exec clear expire key task")
select {
case <-time.After(time.Duration(c.Interval) *time.Second):
if keys := c.cookieMap.GetExpireKeys(); len(keys) != 0 {
for _,key := range keys{
logger.Info("clear expire key:%v",key)
c.Del(key)
}
}
}
}
}
package cache
import (
"cache-system/logger"
"time"
)
var cache ICache
var currentSize int64
func InitMCache() {
logger.Info("init cache instance,cap:%v","256MB")
cache = NewCache("256MB",5)
}
func SetMaxMemory(size string) bool{
logger.Info("exec cache.SetMaxMemory,value:%v",size)
return cache.SetMaxMemory(size)
}
func Set(key string, val interface{}, expire int64){
var ex time.Duration = time.Duration(expire* int64(1000000000))
logger.Info("exec cache.Set,key:%v,value:%v,expire:%v",key,val,expire)
cache.Set(key,val,ex)
}
func Get(key string) (interface{}, bool) {
v,t := cache.Get(key)
logger.Info("exec cache.Get,in-value:%v,out-value:%v,status:%v",key,v,t)
return v,t
}
func Del(key string) bool {
t := cache.Del(key)
logger.Info("exec cache.Del, value:%v",key)
return t
}
func Exists(key string) bool {
t := cache.Exists(key)
logger.Info("exec cache.Exists,value:%v,status:%v",key,t)
return t
}
func Flush() bool {
t := cache.Flush()
logger.Info("exec cache.Flush(),ret-value:%v",t)
return t
}
func Keys() int64 {
t := cache.Keys()
logger.Info("exec cache.Keys, ret-value:%v",t)
return t
}
func ClearExpireNode(){
cache.ClearExpireNode()
}
package cache
import (
"cache-system/logger"
"fmt"
"runtime"
"testing"
"time"
)
func init() {
config := make(map[string]string,1)
config["log_level"] = "debug"
logger.InitLogger("console",config)
InitMCache()
}
func TestSet(t *testing.T) {
Set("name","mfz",5)
time.Sleep(5*time.Second)
Set("age","22",25)
time.Sleep(5*time.Second)
Set("work","it-dev",40)
}
func TestGet(t *testing.T) {
value,ok := Get("name")
if ok {
fmt.Printf("name:%v\n",value)
}else {
t.Errorf("Get key:%v is not exists","name")
}
select {
}
}
func MStat(t *testing.T) {
type MemStatus struct {
All uint32 `json:"all"`
Used uint32 `json:"used"`
Free uint32 `json:"free"`
Self uint64 `json:"self"`
}
memStat := new(runtime.MemStats)
for i:=0; i < 200000; i++{
runtime.ReadMemStats(memStat)
mem := MemStatus{}
mem.Self = memStat.Alloc
time.Sleep(1*time.Second)
}
}
package main
import (
"cache-system/logger"
"fmt"
"math/rand"
"time"
)
import "cache-system/cache"
func init(){
rand.Seed(time.Now().UnixNano())
}
func InitLog(){
config := make(map[string]string,1)
config["log_level"] = "debug"
logger.InitLogger("console",config)
}
func InitCache(){
cache.InitMCache()
}
func main(){
InitLog()
InitCache()
for i:= 0; i < 500; i++{
cache.Set("name:"+fmt.Sprintf("%d",i+1),"tom:"+fmt.Sprintf("%d",i+1),rand.Int63n(10000))
}
fmt.Printf("get cache table size:%d\n",cache.Keys())
val,ok :=cache.Get("name:100")
fmt.Printf("get name:100 value:%v, status:%v\n",val,ok)
cache.Del("name:100")
fmt.Printf("get name:100 key:%v\n",cache.Exists("name:100"))
time.Sleep(2*time.Second)
go cache.ClearExpireNode()
select {
}
}