golang实现一个简易的缓存系统

项目结构:
├── 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 { //阻塞等待

	}
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值