项目结构: ├── 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" /** 该程序需要满⾜足以下要求: 1. 支持设定过期时间,精度为秒级。 2. 支持设定最⼤大内存,当内存超出时候做出合理理的处理理。 3. 支持并发安全。 4. 为简化编程细节,无需实现数据落地。 */ /** ⽀支持过期时间和最⼤大内存⼤大⼩小的的内存缓存库。 */ type ICache interface { //size 是⼀一个字符串串。⽀支持以下参数: 1KB,100KB,1MB,2MB,1GB 等 SetMaxMemory(size string) bool // 设置⼀一个缓存项,并且在expire时间之后过期 Set(key string, val interface{}, expire time.Duration) // 获取⼀一个值 Get(key string) (interface{}, bool) // 删除⼀一个值 Del(key string) bool // 检测⼀一个值 是否存在 Exists(key string) bool // 情况所有值 Flush() bool // 返回所有的key 多少 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++ 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 } //在尾部添加数据,需要从头部开始遍历,直到nil 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 { //index小于0就放在首部 link.Add(key,value,expire) return true } else if index > link.Size(){ //index大于 长度就放在尾部 link.Append(key,value,expire) return true }else { var count int64 = 0 //找到index之前的元素 for count < (index -1 ){ node = node.Next count +=1 } //已经找到index之前的元素 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 } //检查这个key是否过期 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 //node = nil } return true } //获取所有过期的keys 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 //1KB,100KB,1MB,2MB,1GB size int64 cookieMap *linkedList //存在cache 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 } // 设置⼀一个缓存项,并且在expire时间之后过期 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) //Add方法在头部插入 } 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() } // 返回所有的key 多少 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() { //默认初始化一个cache实例,并设置可用存储不能过物理内存可用容量和总容量 logger.Info("init cache instance,cap:%v","256MB") cache = NewCache("256MB",5) //可用存储容量 //go clearExpireNode() //执行清理任务 } func SetMaxMemory(size string) bool{ logger.Info("exec cache.SetMaxMemory,value:%v",size) return cache.SetMaxMemory(size) } // 设置⼀一个缓存项,并且在expire时间之后过期 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 } // 返回所有的key 多少 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) //10秒后过期 time.Sleep(5*time.Second) Set("age","22",25) //10秒后过期 time.Sleep(5*time.Second) Set("work","it-dev",40) //10秒后过期 } 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)) //time.Sleep(200*time.Millisecond) } /* time.Sleep(200*time.Millisecond) cache.Flush() time.Sleep(200*time.Millisecond) fmt.Printf("get cache table size:%d\n",cache.Keys()) time.Sleep(200*time.Millisecond) */ fmt.Printf("get cache table size:%d\n",cache.Keys()) //查询name100 key的值 val,ok :=cache.Get("name:100") fmt.Printf("get name:100 value:%v, status:%v\n",val,ok) //删除name100 key cache.Del("name:100") //查询name100 key是否删除成功 fmt.Printf("get name:100 key:%v\n",cache.Exists("name:100")) time.Sleep(2*time.Second) //等待两秒后开清理过期任务 go cache.ClearExpireNode() select { //阻塞等待 } }