Skip to content

Commit

Permalink
红黑树+小根堆实现的基于优先级的本地缓存 (#20)
Browse files Browse the repository at this point in the history
* 红黑树存储和小根堆优先级

* list 和 set 的实现

* 补充单元测试

* 补充单元测试

* 补充单元测试

* 补充单元测试

* 小根堆改成优先级队列

* ekit 改成 dev 分支

* 优先级方案改进

* 把和优先级有关的操作全部从缓存里抽出来

* 移除复杂的优先级支持逻辑(lru,lfu),只保留最基础的优先级逻辑

* 移除结点类型;所有结点参与淘汰;

* 调整 setnx 的逻辑,移除无效的代码

* 处理 go mod 依赖问题

* 测试用例补全加锁逻辑

* 修改 ticker 的用法
  • Loading branch information
KelipuTe authored Oct 13, 2023
1 parent cc85ba2 commit dda9743
Show file tree
Hide file tree
Showing 6 changed files with 2,187 additions and 3 deletions.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/ecodeclub/ecache
go 1.20

require (
github.com/ecodeclub/ekit v0.0.8
github.com/ecodeclub/ekit v0.0.8-0.20230925161647-c5bfbd460261
github.com/redis/go-redis/v9 v9.1.0
github.com/stretchr/testify v1.8.1
go.uber.org/mock v0.2.0
Expand All @@ -15,5 +15,6 @@ require (
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/hashicorp/golang-lru/v2 v2.0.6
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sync v0.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/ecodeclub/ekit v0.0.8 h1:861Aot0GvD5ueREEYDVYc1oIhDuFyg6MTxIyiOa4Pvw=
github.com/ecodeclub/ekit v0.0.8/go.mod h1:OqTojKeKFTxeeAAUwNIPKu339SRkX6KAuoK/8A5BCEs=
github.com/ecodeclub/ekit v0.0.8-0.20230925161647-c5bfbd460261 h1:FunYsaj58DVk4iIBXeU8hwdbvlGS1hc7ZbWXOx/+Vj0=
github.com/ecodeclub/ekit v0.0.8-0.20230925161647-c5bfbd460261/go.mod h1:OqTojKeKFTxeeAAUwNIPKu339SRkX6KAuoK/8A5BCEs=
github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM=
github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand All @@ -26,6 +26,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU=
go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
21 changes: 21 additions & 0 deletions memory/priority/priority.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2023 ecodeclub
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package priority

// Priority 如果传进来的元素没有实现该接口,则默认优先级为0
type Priority interface {
// GetPriority 获取元素的优先级
GetPriority() int
}
119 changes: 119 additions & 0 deletions memory/priority/rbtree_cache_node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2023 ecodeclub
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package priority

import (
"time"

"github.com/ecodeclub/ekit/list"
"github.com/ecodeclub/ekit/set"

"github.com/ecodeclub/ekit"
)

// rbTreeCacheNode 缓存结点
type rbTreeCacheNode struct {
key string //键
value any //值
deadline time.Time //有效期,默认0,永不过期
priority int //优先级
isDeleted bool //是否被删除
}

func newKVRBTreeCacheNode(key string, value any, expiration time.Duration) *rbTreeCacheNode {
node := &rbTreeCacheNode{
key: key,
value: value,
}
node.setExpiration(expiration)
return node
}

func newListRBTreeCacheNode(key string) *rbTreeCacheNode {
return &rbTreeCacheNode{
key: key,
value: list.NewLinkedList[any](),
}
}

func newSetRBTreeCacheNode(key string, initSize int) *rbTreeCacheNode {
return &rbTreeCacheNode{
key: key,
value: set.NewMapSet[any](initSize),
}
}

func newIntRBTreeCacheNode(key string) *rbTreeCacheNode {
return &rbTreeCacheNode{
key: key,
value: int64(0),
}
}

// setExpiration 设置有效期
func (node *rbTreeCacheNode) setExpiration(expiration time.Duration) {
var deadline time.Time
if expiration != 0 {
deadline = time.Now().Add(expiration)
}
node.deadline = deadline
}

// replace 重新设置缓存结点的value和有效期
func (node *rbTreeCacheNode) replace(value any, expiration time.Duration) {
node.value = value
node.setExpiration(expiration)
}

// beforeDeadline 检查传入的时间是不是在有效期之前
func (node *rbTreeCacheNode) beforeDeadline(checkTime time.Time) bool {
if node.deadline.IsZero() {
return true
}
return checkTime.Before(node.deadline)
}

// truncate 清空缓存结点中的数据
func (node *rbTreeCacheNode) truncate() {
var nilValue any
node.value = nilValue
node.isDeleted = true
}

// comparatorRBTreeCacheNodeByKey 缓存结点根据key的比较方式(给红黑树用)
func comparatorRBTreeCacheNodeByKey() ekit.Comparator[string] {
return func(src string, dst string) int {
if src < dst {
return -1
} else if src == dst {
return 0
} else {
return 1
}
}
}

// comparatorRBTreeCacheNodeByPriority 缓存结点根据优先级的比较方式(给优先级队列用)
func comparatorRBTreeCacheNodeByPriority() ekit.Comparator[*rbTreeCacheNode] {
return func(src *rbTreeCacheNode, dst *rbTreeCacheNode) int {
if src.priority < dst.priority {
return -1
} else if src.priority == dst.priority {
return 0
} else {
return 1
}
}
}
Loading

0 comments on commit dda9743

Please sign in to comment.