2021-10-04 00:54:25 +00:00
|
|
|
package skiplist
|
|
|
|
|
|
|
|
import (
|
2022-07-29 07:17:28 +00:00
|
|
|
"github.com/seaweedfs/seaweedfs/weed/glog"
|
2022-04-18 02:35:43 +00:00
|
|
|
"golang.org/x/exp/slices"
|
2022-08-17 19:05:07 +00:00
|
|
|
"google.golang.org/protobuf/proto"
|
2021-10-04 00:54:25 +00:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type NameBatch struct {
|
|
|
|
key string
|
|
|
|
names map[string]struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (nb *NameBatch) ContainsName(name string) (found bool) {
|
|
|
|
_, found = nb.names[name]
|
|
|
|
return
|
|
|
|
}
|
|
|
|
func (nb *NameBatch) WriteName(name string) {
|
|
|
|
if nb.key == "" || strings.Compare(nb.key, name) > 0 {
|
|
|
|
nb.key = name
|
|
|
|
}
|
|
|
|
nb.names[name] = struct{}{}
|
|
|
|
}
|
|
|
|
func (nb *NameBatch) DeleteName(name string) {
|
|
|
|
delete(nb.names, name)
|
|
|
|
if nb.key == name {
|
|
|
|
nb.key = ""
|
|
|
|
for n := range nb.names {
|
|
|
|
if nb.key == "" || strings.Compare(nb.key, n) > 0 {
|
|
|
|
nb.key = n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func (nb *NameBatch) ListNames(startFrom string, visitNamesFn func(name string) bool) bool {
|
|
|
|
var names []string
|
2021-10-04 08:01:31 +00:00
|
|
|
needFilter := startFrom != ""
|
2021-10-04 00:54:25 +00:00
|
|
|
for n := range nb.names {
|
|
|
|
if !needFilter || strings.Compare(n, startFrom) >= 0 {
|
|
|
|
names = append(names, n)
|
|
|
|
}
|
|
|
|
}
|
2023-09-25 16:16:33 +00:00
|
|
|
slices.SortFunc(names, func(a, b string) int {
|
|
|
|
return strings.Compare(a, b)
|
2021-10-04 00:54:25 +00:00
|
|
|
})
|
|
|
|
for _, n := range names {
|
|
|
|
if !visitNamesFn(n) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewNameBatch() *NameBatch {
|
|
|
|
return &NameBatch{
|
|
|
|
names: make(map[string]struct{}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func LoadNameBatch(data []byte) *NameBatch {
|
|
|
|
t := &NameBatchData{}
|
|
|
|
if len(data) > 0 {
|
|
|
|
err := proto.Unmarshal(data, t)
|
|
|
|
if err != nil {
|
|
|
|
glog.Errorf("unmarshal into NameBatchData{} : %v", err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nb := NewNameBatch()
|
|
|
|
for _, n := range t.Names {
|
|
|
|
name := string(n)
|
|
|
|
if nb.key == "" || strings.Compare(nb.key, name) > 0 {
|
|
|
|
nb.key = name
|
|
|
|
}
|
|
|
|
nb.names[name] = struct{}{}
|
|
|
|
}
|
|
|
|
return nb
|
|
|
|
}
|
|
|
|
|
|
|
|
func (nb *NameBatch) ToBytes() []byte {
|
|
|
|
t := &NameBatchData{}
|
|
|
|
for n := range nb.names {
|
|
|
|
t.Names = append(t.Names, []byte(n))
|
|
|
|
}
|
|
|
|
data, _ := proto.Marshal(t)
|
|
|
|
return data
|
|
|
|
}
|
|
|
|
|
|
|
|
func (nb *NameBatch) SplitBy(name string) (x, y *NameBatch) {
|
|
|
|
x, y = NewNameBatch(), NewNameBatch()
|
|
|
|
|
|
|
|
for n := range nb.names {
|
|
|
|
// there should be no equal case though
|
|
|
|
if strings.Compare(n, name) <= 0 {
|
|
|
|
x.WriteName(n)
|
|
|
|
} else {
|
|
|
|
y.WriteName(n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|