forked from p93542168/wheat-cache
commit
6bd16eec06
|
@ -3,3 +3,7 @@ package errorx
|
||||||
func LruNotWorkFuncEventErr() error {
|
func LruNotWorkFuncEventErr() error {
|
||||||
return New("the event haven't work of function")
|
return New("the event haven't work of function")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func KeyBaseIsNilErr() error {
|
||||||
|
return New("key base not is nil")
|
||||||
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ const (
|
||||||
type CacheInterface interface {
|
type CacheInterface interface {
|
||||||
Del() error
|
Del() error
|
||||||
Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool)
|
Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool)
|
||||||
Add(key *proto.BaseKey, val structure.KeyBaseInterface)
|
Add(key *proto.BaseKey, val structure.KeyBaseInterface) error
|
||||||
UpdateLruSize(length structure.UpdateLength)
|
UpdateLruSize(length structure.UpdateLength)
|
||||||
DelByKey(key *proto.BaseKey) error
|
DelByKey(key *proto.BaseKey) error
|
||||||
DelToClearSize() error
|
DelToClearSize() error
|
||||||
|
|
|
@ -108,7 +108,11 @@ func (lru *SingleCache) GetDriver() event.DriverInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add 增加
|
//Add 增加
|
||||||
func (lru *SingleCache) Add(key *proto.BaseKey, val structure.KeyBaseInterface) {
|
func (lru *SingleCache) Add(key *proto.BaseKey, val structure.KeyBaseInterface) error {
|
||||||
|
|
||||||
|
if key == nil {
|
||||||
|
return errorx.KeyBaseIsNilErr()
|
||||||
|
}
|
||||||
|
|
||||||
exp := lru.lruTtlManage.setKeys(key)
|
exp := lru.lruTtlManage.setKeys(key)
|
||||||
keyBaseVal := &keyBaseValue{
|
keyBaseVal := &keyBaseValue{
|
||||||
|
@ -119,17 +123,22 @@ func (lru *SingleCache) Add(key *proto.BaseKey, val structure.KeyBaseInterface)
|
||||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
if elVal, ok := lru.lruMap[key.Key]; ok {
|
||||||
lru.li.MoveToFront(elVal)
|
lru.li.MoveToFront(elVal)
|
||||||
elVal.Value = keyBaseVal
|
elVal.Value = keyBaseVal
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
valEl := lru.li.PushFront(keyBaseVal)
|
valEl := lru.li.PushFront(keyBaseVal)
|
||||||
lru.lruMap[key.Key] = valEl
|
lru.lruMap[key.Key] = valEl
|
||||||
//增加大小
|
//增加大小
|
||||||
lru.UpdateLruSize(structure.UpdateLength(valEl.Value.(*keyBaseValue).val.SizeByte()))
|
lru.UpdateLruSize(structure.UpdateLength(valEl.Value.(*keyBaseValue).val.SizeByte()))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 查找key对应的value
|
// Get 查找key对应的value
|
||||||
func (lru *SingleCache) Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool) {
|
func (lru *SingleCache) Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool) {
|
||||||
|
|
||||||
|
if key == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
if elVal, ok := lru.lruMap[key.Key]; ok {
|
||||||
lru.li.MoveToFront(elVal)
|
lru.li.MoveToFront(elVal)
|
||||||
return elVal.Value.(*keyBaseValue).val, true
|
return elVal.Value.(*keyBaseValue).val, true
|
||||||
|
@ -152,6 +161,11 @@ func (lru *SingleCache) Del() error {
|
||||||
|
|
||||||
//DelByKey 根据key删除
|
//DelByKey 根据key删除
|
||||||
func (lru *SingleCache) DelByKey(key *proto.BaseKey) error {
|
func (lru *SingleCache) DelByKey(key *proto.BaseKey) error {
|
||||||
|
|
||||||
|
if key == nil {
|
||||||
|
return errorx.KeyBaseIsNilErr()
|
||||||
|
}
|
||||||
|
|
||||||
if lru.lruMap == nil {
|
if lru.lruMap == nil {
|
||||||
return errorx.New("lru is nil")
|
return errorx.New("lru is nil")
|
||||||
}
|
}
|
||||||
|
@ -194,6 +208,10 @@ func (lru *SingleCache) DelToClearSize() error {
|
||||||
// 更新过期时间
|
// 更新过期时间
|
||||||
func (lru *SingleCache) UpdateTTl(key *proto.BaseKey) error {
|
func (lru *SingleCache) UpdateTTl(key *proto.BaseKey) error {
|
||||||
|
|
||||||
|
if key == nil {
|
||||||
|
return errorx.KeyBaseIsNilErr()
|
||||||
|
}
|
||||||
|
|
||||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
if elVal, ok := lru.lruMap[key.Key]; ok {
|
||||||
expire := lru.lruTtlManage.setKeys(key)
|
expire := lru.lruTtlManage.setKeys(key)
|
||||||
elVal.Value.(*keyBaseValue).expire = expire
|
elVal.Value.(*keyBaseValue).expire = expire
|
||||||
|
|
|
@ -2,11 +2,12 @@ package lru
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gitee.com/timedb/wheatCache/pkg/proto"
|
"gitee.com/timedb/wheatCache/pkg/proto"
|
||||||
"gitee.com/timedb/wheatCache/pkg/structure/stringx"
|
"gitee.com/timedb/wheatCache/pkg/structure/stringx"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTTlCup(t *testing.T) {
|
func TestTTlCup(t *testing.T) {
|
||||||
|
|
|
@ -2,13 +2,14 @@ package lru
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gitee.com/timedb/wheatCache/pkg/event"
|
"gitee.com/timedb/wheatCache/pkg/event"
|
||||||
"gitee.com/timedb/wheatCache/pkg/logx"
|
"gitee.com/timedb/wheatCache/pkg/logx"
|
||||||
"gitee.com/timedb/wheatCache/pkg/proto"
|
"gitee.com/timedb/wheatCache/pkg/proto"
|
||||||
"gitee.com/timedb/wheatCache/pkg/structure/stringx"
|
"gitee.com/timedb/wheatCache/pkg/structure/stringx"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWorker(t *testing.T) {
|
func TestWorker(t *testing.T) {
|
||||||
|
@ -53,6 +54,6 @@ func TestSingleCache_DelToClearSize(t *testing.T) {
|
||||||
workEvent.StartWaitEvent(2 * time.Second)
|
workEvent.StartWaitEvent(2 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(5<<10 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
logx.Info("end size is %d", lru.nowSize)
|
logx.Info("end size is %d", lru.nowSize)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@ type KeyBaseInterface interface {
|
||||||
|
|
||||||
type StringXInterface interface {
|
type StringXInterface interface {
|
||||||
KeyBaseInterface
|
KeyBaseInterface
|
||||||
Set(val string) (string, UpdateLength)
|
Set(string) (string, UpdateLength)
|
||||||
Get() string
|
Get() string
|
||||||
Add(renewal int32) (string, error)
|
Add(int32) (string, error)
|
||||||
Reduce(renewal int32) (string, error)
|
Reduce(int32) (string, error)
|
||||||
Setbit(offer int32, val bool) UpdateLength
|
Setbit(int32, bool) UpdateLength
|
||||||
Getbit(offer int32) (bool, error)
|
Getbit(int32) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,40 +166,120 @@ func (s *SkipList) RemoveAll(score float64) {
|
||||||
s.delSkipListNode(delNode...)
|
s.delSkipListNode(delNode...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearLeft 删除 小等于 score 的全部节点
|
func (s *SkipList) PopLeft(score float64) []interface{} {
|
||||||
func (s *SkipList) ClearLeft(score float64) *skipListNode {
|
endPoint := s.tail
|
||||||
|
|
||||||
head := s.head
|
head := s.head
|
||||||
|
|
||||||
for head.down != nil {
|
for endPoint.score > score {
|
||||||
p := head
|
endPoint = endPoint.pre
|
||||||
for p.score <= score {
|
|
||||||
p = p.next
|
|
||||||
}
|
}
|
||||||
|
|
||||||
head.next = p
|
var valuePoint *skipListNode
|
||||||
p.pre = head
|
for endPoint != nil {
|
||||||
|
// 检查 end 后的节点情况
|
||||||
|
for endPoint.next.score <= score {
|
||||||
|
endPoint = endPoint.next
|
||||||
|
}
|
||||||
|
|
||||||
|
head.next = endPoint.next
|
||||||
|
endPoint.next.pre = head
|
||||||
|
valuePoint = endPoint
|
||||||
|
|
||||||
|
endPoint = endPoint.down
|
||||||
head = head.down
|
head = head.down
|
||||||
}
|
}
|
||||||
|
|
||||||
node := s.searchNode(score)
|
values := make([]interface{}, 0, 100)
|
||||||
for node.score <= score {
|
for valuePoint != nil && valuePoint.score > s.head.score {
|
||||||
node = node.next
|
values = append(values, valuePoint.val)
|
||||||
|
valuePoint = valuePoint.pre
|
||||||
}
|
}
|
||||||
|
|
||||||
oldNode := node.pre
|
return values
|
||||||
head.next = node
|
|
||||||
|
|
||||||
node.pre = head
|
|
||||||
return oldNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SkipList) PopLeft(score float64) []interface{} {
|
func (s *SkipList) PopRight(score float64) []interface{} {
|
||||||
node := s.ClearLeft(score)
|
startPoint := s.head
|
||||||
values := make([]interface{}, 0, 10)
|
|
||||||
for node.score != math.MinInt64 {
|
tail := s.tail
|
||||||
values = append(values, node.val)
|
|
||||||
node = node.pre
|
for startPoint.score < score {
|
||||||
|
startPoint = startPoint.next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var valuePoint *skipListNode
|
||||||
|
for startPoint != nil {
|
||||||
|
// 检查 end 后的节点情况
|
||||||
|
for startPoint.pre.score >= score {
|
||||||
|
startPoint = startPoint.pre
|
||||||
|
}
|
||||||
|
|
||||||
|
tail.pre = startPoint.pre
|
||||||
|
startPoint.pre.next = tail
|
||||||
|
valuePoint = startPoint
|
||||||
|
|
||||||
|
startPoint = startPoint.down
|
||||||
|
tail = tail.down
|
||||||
|
}
|
||||||
|
|
||||||
|
values := make([]interface{}, 0, 100)
|
||||||
|
for valuePoint != nil && valuePoint.score < s.tail.score {
|
||||||
|
values = append(values, valuePoint.val)
|
||||||
|
valuePoint = valuePoint.next
|
||||||
|
}
|
||||||
|
|
||||||
|
return values
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// PopRangeByScore 删除包括 start 到 end 的 score 的全部 value
|
||||||
|
func (s *SkipList) PopRangeByScore(startScore float64, endScore float64) []interface{} {
|
||||||
|
if startScore >= endScore {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
startPoint := s.head
|
||||||
|
endPoint := s.tail
|
||||||
|
|
||||||
|
// 定位删除索引最高级
|
||||||
|
for startPoint.score < startScore {
|
||||||
|
startPoint = startPoint.next
|
||||||
|
}
|
||||||
|
for endPoint.score > endScore {
|
||||||
|
endPoint = endPoint.pre
|
||||||
|
}
|
||||||
|
|
||||||
|
var valuePoint *skipListNode
|
||||||
|
|
||||||
|
for startPoint != nil {
|
||||||
|
// 检查 start 前的节点情况
|
||||||
|
for startPoint.pre.score >= startScore {
|
||||||
|
startPoint = startPoint.pre
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 end 后的节点情况
|
||||||
|
for endPoint.next.score <= endScore {
|
||||||
|
endPoint = endPoint.next
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除节点
|
||||||
|
valuePoint = startPoint
|
||||||
|
startPoint.pre.next = endPoint.next
|
||||||
|
endPoint.next.pre = startPoint.pre
|
||||||
|
|
||||||
|
// 下一级处理
|
||||||
|
startPoint = startPoint.down
|
||||||
|
endPoint = endPoint.down
|
||||||
|
}
|
||||||
|
|
||||||
|
values := make([]interface{}, 0, 100)
|
||||||
|
for valuePoint != nil && valuePoint.score <= endScore {
|
||||||
|
values = append(values, valuePoint.val)
|
||||||
|
valuePoint = valuePoint.next
|
||||||
|
}
|
||||||
|
|
||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,12 @@ package skiplist
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gitee.com/timedb/wheatCache/pkg/logx"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gitee.com/timedb/wheatCache/pkg/logx"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 时间测试
|
// 时间测试
|
||||||
|
@ -66,3 +67,39 @@ func Test_skipList_ClearLeft(t *testing.T) {
|
||||||
require.Equal(t, s.Get(20), nil)
|
require.Equal(t, s.Get(20), nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSkipList_PopRangeByScore(t *testing.T) {
|
||||||
|
startNum := 5
|
||||||
|
endNum := 79
|
||||||
|
result := make([]interface{}, 0)
|
||||||
|
for i := startNum; i <= endNum; i++ {
|
||||||
|
result = append(result, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
s := NewSkipList(14)
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
s.Insert(float64(i), i)
|
||||||
|
}
|
||||||
|
res := s.PopRangeByScore(float64(startNum), float64(endNum))
|
||||||
|
require.Equal(t, res, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSkipList_PopRight(t *testing.T) {
|
||||||
|
score := 33
|
||||||
|
result := make([]interface{}, 0)
|
||||||
|
for i := score; i < 100; i++ {
|
||||||
|
result = append(result, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
s := NewSkipList(14)
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
s.Insert(float64(i), i)
|
||||||
|
}
|
||||||
|
res := s.PopRight(float64(score))
|
||||||
|
require.Equal(t, res, result)
|
||||||
|
s.debugPrint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -32,9 +32,11 @@ func (d *Dao) Set(key *proto.BaseKey, strVal string) (string, error) {
|
||||||
|
|
||||||
// 不存在新建
|
// 不存在新建
|
||||||
strValue := stringx.NewStringSingle()
|
strValue := stringx.NewStringSingle()
|
||||||
result, length := strValue.Set(strVal)
|
result, _ := strValue.Set(strVal)
|
||||||
d.lru.Add(key, strValue)
|
err := d.lru.Add(key, strValue)
|
||||||
d.lru.UpdateLruSize(length)
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue