从零 开始写一个kv存储数据库(一)

NoSql 数据库那么火 那么就让我们来写一个吧

单机存储模块 就是有一个以 map 映射键值对 存储 key value 关系的一个 map 在 redis中 没map数据类型 所以是自己定义的 在go中 是由hashmap这个数据结构的所以 就很简单了。

//存储value 包含 内容 和超时 时间
type Item struct {
	Object interface{} //核心 用来存储数据
	Expiration int64 //每个 键值对 都存在超时时间
}


//item 方法 用来判断有没有过期
func (it Item) Expired() bool{
	if it.Expiration == 0 {
		return false
	}
	//如果 当前 时间 大于过期时间 则 过期
	return time.Now().UnixNano() > it.Expiration
}

const (
	//不会过期的标志
	NoExpiration time.Duration = -1

	//默认的过期时间
	DefaultExpiration time.Duration = 0
)

用 -1 和 0 代表 2 中kv 的类型 一种是永不过期 一种是会过期的

type Cache struct {

	defaultExpiration time.Duration //默认的过期时间

	items map[string]Item //缓存数据存储

	mu sync.RWMutex  //读写锁

	gcInterval time.Duration //过期数据清理周期

	stopGc chan bool//需要暂停垃圾回收时 触发

}

items map[string]Item 将 一个键 对应 一个Item 用于存放数据
对于过期 的 map里的内容好会单独启动一个携程进行删除

func (c *Cache) gcLoop(){
	fmt.Println("GC Running.....")
	ticker := time.NewTicker(c.gcInterval) //定期执行 gc清除过期数据
	for{
		select {
			case <- ticker.C:
				fmt.Println("GC Start Work")
				c.DeleteExpired()
			case <- c.stopGc:
				ticker.Stop()
				return
			
		}
	}
}


//删除缓存数据项
func (c *Cache) delete(k string) {
	delete(c.items, k)
}
//删除过期数据项
func (c *Cache) DeleteExpired() {
	now := time.Now().UnixNano()
	c.mu.Lock()
	defer c.mu.Unlock()
	//循环遍历删除 过期的键值对
	for k,v := range c.items{
		if v.Expiration > 0 && now > v.Expiration{
			c.delete(k)
		}


	}
}
// 设置数据项, 没有锁操作
func (c *Cache) set(k string, v interface{}, d time.Duration) {
	var e int64
	if d == DefaultExpiration {
		d = c.defaultExpiration
	}
	if d > 0 {
		e = time.Now().Add(d).UnixNano()
	}
	c.items[k] = Item{
		Object:     v,
		Expiration: e,
	}
}

func (c *Cache) Set(k string,v interface{},d time.Duration){
	var e int64
	//如果是 0  表示 使用默认过期时间
	if d == DefaultExpiration {
		//设置为 默认过期时间
		d = c.defaultExpiration
	}
	if d > 0 {
		//计算当前时间 加上 过期时间
		e = time.Now().Add(d).UnixNano()
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	c.items[k] = Item{
		Object:v,
		Expiration:e,
	}
}
func (c *Cache) get(k string) (interface{} ,bool){
	//从hash表中取出value
	item,found := c.items[k]
	if !found {
		return nil,false
	}
	//取出的对象有没有过期
	if item.Expired() {
		return nil,false
	}
	return item.Object,true

}
func (c *Cache) Add(k string,v interface{},d time.Duration) error{
	c.mu.Lock()
	//如果已存在 无法添加
	if _,found := c.get(k);found {
		c.mu.Unlock()
		return fmt.Errorf("Item %s already exists",k)
	}
	c.set(k, v, d)
	c.mu.Unlock()
	return nil

}

//获取value 如果不存在 返回nil false
func (c *Cache) Get(k string)(interface{},bool){
	c.mu.RLock()
	defer c.mu.RUnlock()
	item,found := c.items[k]
	if !found {
		return nil,false
	}
	if item.Expired() {
		return nil,false
	}
	return item.Object,true
}

func (c *Cache) Replace(k string,v interface{},d time.Duration) error{
	c.mu.Lock()
	_,found := c.get(k)
	if !found {
		fmt.Errorf("Item %s doesn's exist",k)
	}
	c.set(k,v,d)
	c.mu.Unlock()
	return nil
}

func (c *Cache) Delete(k string){
	c.mu.Lock()
	c.delete(k)
	c.mu.Unlock()
}

func (c *Cache) Save(w io.Writer) (err error){
	enc := gob.NewEncoder(w)
	defer func(){
		if x := recover();x != nil{
			err = fmt.Errorf("Error registring item type with gob library!")
		}
	}()
	c.mu.RLock()
	defer c.mu.RUnlock()
	for _, v := range c.items{
		gob.Register(v.Object)
	}
	err = enc.Encode(&c.items)
	return
}
//保存文本到文件中
func (c *Cache) SaveToFile(file string) error{
	f,err := os.Create(file)
	if err != nil{
		return err
	}
	if err = c.Save(f) ;err != nil{
		f.Close()
		return err
	}
	return f.Close()
}
//从 io.Reader 中读取数据
func (c *Cache) Load(r io.Reader) error{
	dec := gob.NewDecoder(r)
	items := map[string]Item{}
	err := dec.Decode(&items)
	if err == nil{
		c.mu.Lock()
		defer c.mu.Unlock()
		for k,v := range items{
			ov,found := c.items[k]
			if !found || ov.Expired() {
				c.items[k] = v
			}
		}
	}
	return err
}
//文件中加载数据
func (c *Cache) LoadFile(file string) error{
	f,err := os.Open(file)
	if err != nil{
		return err
	}
	if err = c.Load(f);err != nil{
		f.Close()
		return err
	}
	return f.Close()
}
//返回缓存数据项的数量
func (c *Cache) Count() int{
	c.mu.RLock()
	defer c.mu.RUnlock()
	return len(c.items)
}

//清空缓存
func (c *Cache) Flush() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.items = map[string]Item{}
}
//停止过期缓存清理
func (c *Cache) StopGc(){
	c.stopGc <- true
}

func (c *Cache) Increment(key string,num int){
	if  v,ok := c.Get(key);ok{
		//取interface类型
		if val, ok := v.(int); ok {
			val = val + num
			c.Replace(key,val,0)
		}
	}
}

//创建缓存系统
func NewCache(defaulteExpiration,gcInterval time.Duration) *Cache{

	c:= &Cache{
		defaultExpiration: ObjectConfig.DefaulteExpiration,
		items:             make(map[string]Item,ObjectConfig.MaxCacheLen),
		gcInterval:        ObjectConfig.GCInterval,
		stopGc:            make(chan bool),
	}

	if defaulteExpiration != 0 {
		c.defaultExpiration = defaulteExpiration
	}
	if gcInterval != 0{
		c.gcInterval =gcInterval
	}
	//开启gc
	go c.gcLoop()

	return c
}


发布了67 篇原创文章 · 获赞 5 · 访问量 3158

猜你喜欢

转载自blog.csdn.net/weixin_41315492/article/details/103927612