思路
1,map+双向链表来实现,双向链表的表头记录最新的数据,
get,set操作都会把节点插入表头,这样的好处是保证热点数据在前面,
非热单数据在后面;
2,定时器按配置定时从链尾开始扫描数据,过期的数据被清除,如果实在没有
过期时间,但是又超出内存限制的情况就删除链尾的最后一个节点
3,哈希表记录每一个节点的数据,set(),get(),exist(),del(),keys()
操作的时间复杂度为常数级别O(1)
4,并发时的线程安全控制用读写锁来实现,即set,del,操作时加上c.lock.Lock(), 读取时加上c.lock.RLock()
5,目前这个只实现了string类型数据的读写管理
interface.go
package cache
import "time"
type CacheInterface 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
}
handle.go
package cache
import (
"fmt"
"log"
"sync"
"time"
)
type Cache struct {
Head *listNode
Tail *listNode
MemoryUsed int64
Maxmemory int64
M maps
Count int64
lock sync.RWMutex
}
type listNode struct {
key string
val interface{} //节点数据
expire time.Time //过期时间
pre *listNode //前一个节点地址
next *listNode //后一个节点地址
}
type maps map[string]*listNode
func (m maps)Init() maps{
cm := make(map[string]*listNode)
return cm
}
func (m maps) Set(key string, p *listNode) {
m[key] = p
}
func (m maps) Get(key string) (*listNode, bool) {
if p, ok := m[key]; ok {
return p,ok
}
return nil, false
}
func (m maps) Detele(key string) {
delete(m,key)
}
func (c *Cache) GetCurrent(current *listNode) interface{} {
return current.val
}
func (c *Cache) SetMaxMemory(size string) bool {
if len(size) == 0 {
return false
}
switch size {
case "1kb":
c.Maxmemory = KB1
case "1mb":
c.Maxmemory = MB1
case "2mb":
c.Maxmemory = MB2
case "1gb":
c.Maxmemory = GB1
}
return true
}
func (c *Cache) Init() *Cache{
c.Head = &listNode{}
c.Tail = &listNode{}
//建头尾两个为节点,初始状态为首尾相连
c.Head.next = c.Tail
c.Head.pre = nil
c.Tail.pre = c.Head
c.Tail.next = nil
c.Count = 0
c.MemoryUsed = 0
c.lock = sync.RWMutex{}
//初始化map
pm := &maps{}
c.M = pm.Init()
return c
}
func (c *Cache) addCount() int64 {
c.Count ++
return c.Count
}
func (c *Cache) decCount() int64 {
c.Count --
return c.Count
}
func (c *Cache) Set(key string, val interface{}, expire time.Duration) {
c.lock.Lock()
defer c.lock.Unlock()
if val == nil {
return
}
// 查看内存配置,如果超过就遍历链表释放内存
if c.MemoryUsed + int64(len(val.(string))) >= c.Maxmemory {
c.Lru()
}
//再次检查,如果超过内存配置就不能写
if c.MemoryUsed + int64(len(val.(string))) >= c.Maxmemory {
return
}
// 查找Map,如果map存在,则从map拿出所在的位置(指针),然后插入表头,同时调整链表前后节点的位置
if v,ok := c.M.Get(key); ok {
c.takeOut(v)
v.val = val
c.insertToHead(v)
fmt.Printf("Set key:%s,val:%v,first:%v\n",key,v.val,c.Head.next.val)
}else{//如果不存在,则新建一个节点插入表头
node := &listNode{}
node.key = key
node.val = val
now := time.Now()
node.expire = now.Add(time.Duration(expire)*time.Second)
c.insertToHead(node)
//个数统计
c.addCount()
// 把最新的位置写入map
c.M.Set(key,node)
//内存统计
c.incMemoryUsed(node)
}
}
func (c *Cache) Get(key string) (interface{}, bool) {
c.lock.RLock()
defer c.lock.RUnlock()
// 1,先从map中找,如果不存在,返回false
current,ok := c.M.Get(key)
if !ok {
return nil,false
}
// 2,如果存在,找出相应的位置,并检查key是否过期
now := time.Now()
if now.After(current.expire) {
//如果key已经过期,再删除Key,即调整链表的前后位置,返回false
c.takeOut(current)
//清除map表中的Key
c.M.Detele(key)
//扣减相应的内存
c.decMemoryUsed(current)
}else{
//如果key还未过期,调整位置,把此key的位置插入表头,并更新所在map的位置
if c.Head.next != current {
//先抽出节点
c.takeOut(current)
//把抽出的节点放到第表头
c.insertToHead(current)
}
}
return current.val,true
}
func (c *Cache) Del(key string) bool {
c.lock.Lock()
defer c.lock.Unlock()
// 1,查找map,如果存在再往下处理
current, ok := c.M.Get(key)
if !ok {
return false
}
fmt.Printf("Del:key:%s,val:%v\n",key,current.val)
// map存在,找出相应的地址,调整链表前后节点的位置
c.takeOut(current)
// 删除在map中的key
c.M.Detele(key)
//减少一个
c.decCount()
//内存统计
c.decMemoryUsed(current)
return true
}
func (c *Cache) Exists(key string) bool {
// 查找map 看是否存在,返回对应的true或false
if _,ok := c.M.Get(key); ok {
return true
}else{
return false
}
}
func (c *Cache) Flush() bool {
c.lock.Lock()
defer c.lock.Unlock()
//清空map
for key := range c.M {
c.M.Detele(key)
}
return true
}
func (c *Cache) Keys() int64 {
return c.Count
}
func (c *Cache) size(current *listNode) int64 {
strlen := len(current.val.(string)) + len(current.key) + 24 + 8 + 8
return int64(strlen)
}
func (c *Cache) Lru() {
log.Println("Lru start....")
log.Printf("Berfore Lru memoryUsed:%d,count:%d,keys\n",c.MemoryUsed,c.Count)
// 遍历链表,从表尾开始遍历
now := time.Now()
current := c.Tail
m := c.M
count := 0
//从表尾开始,清除过期的数据
for current.pre != nil {
if now.After(current.expire) {
if current.val != nil {
c.takeOut(current)
key := current.key
m.Detele(key)
c.decMemoryUsed(current)
c.decCount()
count ++
log.Printf("Clear data key:%s,val:%s\n",key,current.val)
}
}
current = current.pre
}
//如果一个都没有过期,则删除最后一个节点
if count == 0 && c.MemoryUsed >= c.Maxmemory{
current := c.Tail.pre
if current.val != nil {
c.takeOut(current)
key := current.key
m.Detele(key)
c.decMemoryUsed(current)
c.decCount()
log.Printf("Clear data key:%s,val:%s\n",key,current.val)
}
}
log.Println("Lru ending....")
log.Printf("After Lru memoryUsed:%d,count:%d\n",c.MemoryUsed,c.Count)
}
//内存增加
func (c *Cache) incMemoryUsed(current *listNode) {
strlen := c.size(current)
c.MemoryUsed = c.MemoryUsed + int64(strlen)
}
//内存扣减
func (c *Cache) decMemoryUsed(current *listNode) {
strlen := c.size(current)
c.MemoryUsed = c.MemoryUsed - int64(strlen)
}
//取出一个节点
func (c *Cache) takeOut(current *listNode) {
pre := current.pre
next := current.next
pre.next = next
next.pre = pre
}
//把节点插入链头
func (c *Cache) insertToHead(current *listNode) {
oldFirst := c.Head.next
oldFirst.pre = current
current.next = oldFirst
current.pre = c.Head
c.Head.next = current
}
func (c *Cache) Run(){
dt := time.Duration(time.Second * CLEAR_DATA_TIMER)
t := time.NewTicker(dt)
defer t.Stop()
for{
select {
case <-t.C :
c.Lru()
}
}
}
main.go
func main() {
var ch cache.CacheInterface
p := &cache.Cache{}
c := p.Init()
ch = c
ch.SetMaxMemory("1kb")
ch.Set("test1","garyyang19999sdfffffffffffffffff",300)
record,ok := ch.Get("test1")
fmt.Println(record,ok)
ch.Set("test2","garyyang19999sdfffffffffffffffff",300)
fmt.Printf("ch.Exits(test2):%v\n",ch.Exists("test2"))
ch.Set("test4","test4",4)
ch.Set("test5","test5",5)
ch.Set("test6","test6",6)
ch.Set("test7","test7",7)
ch.Set("test8","test8",8)
go c.Run()
sigs := make(chan os.Signal)
signal.Notify(sigs)
<- sigs
}